* Elvis Stansvik
* Eranroz
* Erwin Dokter
+* Étienne Beaulé
* Federico Leva
* FunPika
* fomafix
configurations are $wgDeletedDirectory and $wgHashedUploadDirectory.
* The deprecated $wgUseCommaCount variable has been removed.
* $wgEnableSorbs and $wgSorbsUrl have been removed.
+* The UserCryptPassword and UserComparePassword hooks are no longer called. Any extensions
+ using them must be updated to use the Password Hashing API.
=== New features in 1.24 ===
* Added a new hook, "WhatLinksHereProps", to allow extensions to annotate
* (bug 67042) Added support for the HTML5 <rtc> tag for East Asian typography.
* Upgrade Sinon.JS to 1.10.3.
* Added the es5-shim polyfill for older or non-compliant javascript engines.
-* Upgrade jQuery Cookie to v1.2.0.
+* Upgrade jQuery Cookie to v1.3.1.
* (bug 20476) Add a "viewsuppressed" user right to be able to view
suppressed content but not suppress it ("suppressrevision" right).
* Added a new hook, "OutputPageScriptsForBottomQueue", to add modules to the
no longer be displayed in the sidebar when $wgInterwikiMagic is true.
* New special page, MyLanguages, to redirect users to subpages with localised
versions of a page. (Integrated from Extension:Translate)
+* MediaWiki now supports multiple password types, including bcrypt and PBKDF2.
+ The default type can be changed with $wgPasswordDefault and the type
+ configurations can be changed with $wgPasswordConfig.
+* Skins can now define custom styles for default ResourceLoader modules using
+ the $wgResourceModuleSkinStyles global. See the Vector skin for examples.
=== Bug fixes in 1.24 ===
* (bug 49116) Footer copyright notice is now always displayed in user language
* Removed maintenance script importTextFile.php. Use edit.php script instead.
* A _from_namespace field has been added to the templatelinks, pagelinks,
and filelinks tables. Run update.php to apply this change to the schema.
+* Removed File::sha1Base36(). (deprecated since 1.19)
+* Removed File::getPropsFromPath(). (deprecated since 1.19)
==== Renamed classes ====
* CLDRPluralRuleConverter_Expression to CLDRPluralRuleConverterExpression
$user: User (object) that will clear the message
$oldid: ID of the talk page revision being viewed (0 means the most recent one)
-'UserComparePasswords': Called when checking passwords, return false to
-override the default password checks.
-&$hash: String of the password hash (from the database)
-&$password: String of the plaintext password the user entered
-&$userId: Integer of the user's ID or Boolean false if the user ID was not
- supplied
-&$result: If the hook returns false, this Boolean value will be checked to
- determine if the password was valid
-
'UserCreateForm': change to manipulate the login form
$template: SimpleTemplate instance for the form
-'UserCryptPassword': Called when hashing a password, return false to implement
-your own hashing method.
-&$password: String of the plaintext password to encrypt
-&$salt: String of the password salt or Boolean false if no salt is provided
-&$wgPasswordSalt: Boolean of whether the salt is used in the default hashing
- method
-&$hash: If the hook returns false, this String will be used as the hash
-
'UserEffectiveGroups': Called in User::getEffectiveGroups().
$user: User to get groups for
&$groups: Current effective groups
'Preprocessor_Hash' => 'includes/parser/Preprocessor_Hash.php',
'StripState' => 'includes/parser/StripState.php',
+ # includes/password
+ 'BcryptPassword' => 'includes/password/BcryptPassword.php',
+ 'InvalidPassword' => 'includes/password/InvalidPassword.php',
+ 'LayeredParameterizedPassword' => 'includes/password/LayeredParameterizedPassword.php',
+ 'MWSaltedPassword' => 'includes/password/MWSaltedPassword.php',
+ 'MWOldPassword' => 'includes/password/MWOldPassword.php',
+ 'ParameterizedPassword' => 'includes/password/ParameterizedPassword.php',
+ 'Password' => 'includes/password/Password.php',
+ 'PasswordFactory' => 'includes/password/PasswordFactory.php',
+ 'Pbkdf2Password' => 'includes/password/Pbkdf2Password.php',
+ 'EncryptedPassword' => 'includes/password/EncryptedPassword.php',
+
# includes/profiler
'Profiler' => 'includes/profiler/Profiler.php',
'ProfilerMwprof' => 'includes/profiler/ProfilerMwprof.php',
'ResourceLoaderContext' => 'includes/resourceloader/ResourceLoaderContext.php',
'ResourceLoaderFileModule' => 'includes/resourceloader/ResourceLoaderFileModule.php',
'ResourceLoaderFilePageModule' => 'includes/resourceloader/ResourceLoaderFilePageModule.php',
+ 'ResourceLoaderFilePath' => 'includes/resourceloader/ResourceLoaderFilePath.php',
'ResourceLoaderLESSFunctions' => 'includes/resourceloader/ResourceLoaderLESSFunctions.php',
'ResourceLoaderModule' => 'includes/resourceloader/ResourceLoaderModule.php',
'ResourceLoaderNoscriptModule' => 'includes/resourceloader/ResourceLoaderNoscriptModule.php',
*/
$wgResourceModules = array();
+/**
+ * Skin-specific styles for resource modules.
+ *
+ * These are later added to the 'skinStyles' list of the existing module. The 'styles' list can
+ * not be modified or disabled.
+ *
+ * For example, here is a module "bar" and how skin Foo would provide additional styles for it.
+ *
+ * @par Example:
+ * @code
+ * $wgResourceModules['bar'] = array(
+ * 'scripts' => 'resources/bar/bar.js',
+ * 'styles' => 'resources/bar/main.css',
+ * );
+ *
+ * $wgResourceModuleSkinStyles['foo'] = array(
+ * 'bar' => 'skins/Foo/bar.css',
+ * );
+ * @endcode
+ *
+ * This is mostly equivalent to:
+ *
+ * @par Equivalent:
+ * @code
+ * $wgResourceModules['bar'] = array(
+ * 'scripts' => 'resources/bar/bar.js',
+ * 'styles' => 'resources/bar/main.css',
+ * 'skinStyles' => array(
+ * 'foo' => skins/Foo/bar.css',
+ * ),
+ * );
+ * @endcode
+ *
+ * If the module already defines its own entry in `skinStyles` for a given skin, then
+ * $wgResourceModuleSkinStyles is ignored.
+ *
+ * If a module defines a `skinStyles['default']` the skin may want to extend that instead
+ * of replacing them. This can be done using the `+` prefix.
+ *
+ * @par Example:
+ * @code
+ * $wgResourceModules['bar'] = array(
+ * 'scripts' => 'resources/bar/bar.js',
+ * 'styles' => 'resources/bar/basic.css',
+ * 'skinStyles' => array(
+ * 'default' => 'resources/bar/additional.css',
+ * ),
+ * );
+ * // Note the '+' character:
+ * $wgResourceModuleSkinStyles['+foo'] = array(
+ * 'bar' => 'skins/Foo/bar.css',
+ * );
+ * @endcode
+ *
+ * This is mostly equivalent to:
+ *
+ * @par Equivalent:
+ * @code
+ * $wgResourceModules['bar'] = array(
+ * 'scripts' => 'resources/bar/bar.js',
+ * 'styles' => 'resources/bar/basic.css',
+ * 'skinStyles' => array(
+ * 'default' => 'resources/bar/additional.css',
+ * 'foo' => array(
+ * 'resources/bar/additional.css',
+ * 'skins/Foo/bar.css',
+ * ),
+ * ),
+ * );
+ * @endcode
+ *
+ * In other words, as a module author, use the `styles` list for stylesheets that may not be
+ * disabled by a skin. To provide default styles that may be extended or replaced,
+ * use `skinStyles['default']`.
+ *
+ * As with $wgResourceModules, paths default to being relative to the MediaWiki root.
+ * You should always provide a localBasePath and remoteBasePath (or remoteExtPath/remoteSkinPath).
+ * Either for all skin styles at once (first example below) or for each module separately (second
+ * example).
+ *
+ * @par Example:
+ * @code
+ * $wgResourceModuleSkinStyles['foo'] = array(
+ * 'bar' => 'bar.css',
+ * 'quux' => 'quux.css',
+ * 'remoteSkinPath' => 'Foo',
+ * 'localBasePath' => __DIR__,
+ * );
+ *
+ * $wgResourceModuleSkinStyles['foo'] = array(
+ * 'bar' => array(
+ * 'bar.css',
+ * 'remoteSkinPath' => 'Foo',
+ * 'localBasePath' => __DIR__,
+ * ),
+ * 'quux' => array(
+ * 'quux.css',
+ * 'remoteSkinPath' => 'Foo',
+ * 'localBasePath' => __DIR__,
+ * ),
+ * );
+ * @endcode
+ */
+$wgResourceModuleSkinStyles = array();
+
/**
* Extensions should register foreign module sources here. 'local' is a
* built-in source that is not in this array, but defined by
/**
* For compatibility with old installations set to false
+ * @deprecated since 1.24 will be removed in future
*/
$wgPasswordSalt = true;
*/
$wgInvalidPasswordReset = true;
+/*
+ * Default password type to use when hashing user passwords
+ *
+ * @since 1.24
+ */
+$wgPasswordDefault = 'B';
+
+/**
+ * Configuration for built-in password types. Maps the password type
+ * to an array of options. The 'class' option is the Password class to
+ * use. All other options are class-dependent.
+ *
+ * An advanced example:
+ * @code
+ * $wgPasswordConfig['bcrypt-peppered'] = array(
+ * 'class' => 'EncryptedPassword',
+ * 'underlying' => 'bcrypt',
+ * 'secrets' => array(),
+ * 'cipher' => MCRYPT_RIJNDAEL_256,
+ * 'mode' => MCRYPT_MODE_CBC,
+ * 'cost' => 5,
+ * );
+ * @endcode
+ *
+ * @since 1.24
+ */
+$wgPasswordConfig = array(
+ 'A' => array(
+ 'class' => 'MWOldPassword',
+ ),
+ 'B' => array(
+ 'class' => 'MWSaltedPassword',
+ ),
+ 'pbkdf2-legacyA' => array(
+ 'class' => 'LayeredParameterizedPassword',
+ 'types' => array(
+ 'A',
+ 'pbkdf2',
+ ),
+ ),
+ 'pbkdf2-legacyB' => array(
+ 'class' => 'LayeredParameterizedPassword',
+ 'types' => array(
+ 'B',
+ 'pbkdf2',
+ ),
+ ),
+ 'bcrypt' => array(
+ 'class' => 'BcryptPassword',
+ 'cost' => 9,
+ ),
+ 'pbkdf2' => array(
+ 'class' => 'Pbkdf2Password',
+ 'algo' => 'sha256',
+ 'cost' => '10000',
+ 'length' => '128',
+ ),
+);
+
/**
* Whether to allow password resets ("enter some identifying data, and we'll send an email
* with a temporary password you can use to get back into the account") identified by
}
if ( !$wgRunJobsAsync ) {
- // If running jobs asynchronously has been disabled, run the job here
- // while the user waits
- SpecialRunJobs::executeJobs( $n );
+ // Fall back to running the job here while the user waits
+ $runner = new JobRunner();
+ $runner->run( array( 'maxJobs' => $n ) );
return;
}
if ( !$sock ) {
wfDebugLog( 'runJobs', "Failed to start cron API (socket error $errno): $errstr\n" );
// Fall back to running the job here while the user waits
- SpecialRunJobs::executeJobs( $n );
+ $runner = new JobRunner();
+ $runner->run( array( 'maxJobs' => $n ) );
return;
}
* Int Serialized record version.
* @ingroup Constants
*/
-define( 'MW_USER_VERSION', 9 );
+define( 'MW_USER_VERSION', 10 );
/**
* String Some punctuation to prevent editing from broken text-mangling proxies.
*/
const MAX_WATCHED_ITEMS_CACHE = 100;
+ /**
+ * @var PasswordFactory Lazily loaded factory object for passwords
+ */
+ private static $mPasswordFactory = null;
+
/**
* Array of Strings List of member variables which are saved to the
* shared cache (memcached). Any operation which changes the
'mId',
'mName',
'mRealName',
- 'mPassword',
- 'mNewpassword',
- 'mNewpassTime',
'mEmail',
'mTouched',
'mToken',
'mEmailAuthenticated',
'mEmailToken',
'mEmailTokenExpires',
- 'mPasswordExpires',
'mRegistration',
'mEditCount',
// user_groups table
public function loadDefaults( $name = false ) {
wfProfileIn( __METHOD__ );
+ $passwordFactory = self::getPasswordFactory();
+
$this->mId = 0;
$this->mName = $name;
$this->mRealName = '';
- $this->mPassword = $this->mNewpassword = '';
+ $this->mPassword = $passwordFactory->newFromCiphertext( null );
+ $this->mNewpassword = $passwordFactory->newFromCiphertext( null );
$this->mNewpassTime = null;
$this->mEmail = '';
$this->mOptionOverrides = null;
*/
public function loadFromRow( $row, $data = null ) {
$all = true;
+ $passwordFactory = self::getPasswordFactory();
$this->mGroups = null; // deferred
}
if ( isset( $row->user_password ) ) {
- $this->mPassword = $row->user_password;
- $this->mNewpassword = $row->user_newpassword;
+ // Check for *really* old password hashes that don't even have a type
+ // The old hash format was just an md5 hex hash, with no type information
+ if ( preg_match( '/^[0-9a-f]{32}$/', $row->user_password ) ) {
+ $row->user_password = ":A:{$this->mId}:{$row->user_password}";
+ }
+
+ try {
+ $this->mPassword = $passwordFactory->newFromCiphertext( $row->user_password );
+ } catch ( PasswordError $e ) {
+ wfDebug( 'Invalid password hash found in database.' );
+ $this->mPassword = $passwordFactory->newFromCiphertext( null );
+ }
+
+ try {
+ $this->mNewpassword = $passwordFactory->newFromCiphertext( $row->user_newpassword );
+ } catch ( PasswordError $e ) {
+ wfDebug( 'Invalid password hash found in database.' );
+ $this->mNewpassword = $passwordFactory->newFromCiphertext( null );
+ }
+
$this->mNewpassTime = wfTimestampOrNull( TS_MW, $row->user_newpass_time );
+ $this->mPasswordExpires = wfTimestampOrNull( TS_MW, $row->user_password_expires );
+ }
+
+ if ( isset( $row->user_email ) ) {
$this->mEmail = $row->user_email;
$this->mTouched = wfTimestamp( TS_MW, $row->user_touched );
$this->mToken = $row->user_token;
$this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated );
$this->mEmailToken = $row->user_email_token;
$this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires );
- $this->mPasswordExpires = wfTimestampOrNull( TS_MW, $row->user_password_expires );
$this->mRegistration = wfTimestampOrNull( TS_MW, $row->user_registration );
} else {
$all = false;
}
}
+ /**
+ * Load the user's password hashes from the database
+ *
+ * This is usually called in a scenario where the actual User object was
+ * loaded from the cache, and then password comparison needs to be performed.
+ * Password hashes are not stored in memcached.
+ *
+ * @since 1.24
+ */
+ private function loadPasswords() {
+ if ( $this->getId() !== 0 && ( $this->mPassword === null || $this->mNewpassword === null ) ) {
+ $this->loadFromRow( wfGetDB( DB_MASTER )->selectRow(
+ 'user',
+ array( 'user_password', 'user_newpassword', 'user_newpass_time', 'user_password_expires' ),
+ array( 'user_id' => $this->getId() ),
+ __METHOD__
+ ) );
+ }
+ }
+
/**
* Add the user to the group if he/she meets given criteria.
*
*
* Called implicitly from invalidateCache() and saveSettings().
*/
- private function clearSharedCache() {
+ public function clearSharedCache() {
$this->load();
if ( $this->mId ) {
global $wgMemc;
* through the web interface.
*/
public function setInternalPassword( $str ) {
- $this->load();
$this->setToken();
+ $passwordFactory = self::getPasswordFactory();
if ( $str === null ) {
- // Save an invalid hash...
- $this->mPassword = '';
+ $this->mPassword = $passwordFactory->newFromCiphertext( null );
} else {
- $this->mPassword = self::crypt( $str );
+ $this->mPassword = $passwordFactory->newFromPlaintext( $str );
}
- $this->mNewpassword = '';
+
+ $this->mNewpassword = $passwordFactory->newFromCiphertext( null );
$this->mNewpassTime = null;
}
$this->mNewpassword = '';
$this->mNewpassTime = null;
} else {
- $this->mNewpassword = self::crypt( $str );
+ $this->mNewpassword = self::getPasswordFactory()->newFromPlaintext( $str );
if ( $throttle ) {
$this->mNewpassTime = wfTimestampNow();
}
global $wgAuth;
$this->load();
+ $this->loadPasswords();
if ( wfReadOnly() ) {
return;
}
$this->mTouched = self::newTouchedTimestamp();
if ( !$wgAuth->allowSetLocalPassword() ) {
- $this->mPassword = '';
+ $this->mPassword = self::getPasswordFactory()->newFromCiphertext( null );
}
$dbw = wfGetDB( DB_MASTER );
$dbw->update( 'user',
array( /* SET */
'user_name' => $this->mName,
- 'user_password' => $this->mPassword,
- 'user_newpassword' => $this->mNewpassword,
+ 'user_password' => $this->mPassword->toString(),
+ 'user_newpassword' => $this->mNewpassword->toString(),
'user_newpass_time' => $dbw->timestampOrNull( $this->mNewpassTime ),
'user_real_name' => $this->mRealName,
'user_email' => $this->mEmail,
public static function createNew( $name, $params = array() ) {
$user = new User;
$user->load();
+ $user->loadPasswords();
$user->setToken(); // init token
if ( isset( $params['options'] ) ) {
$user->mOptions = $params['options'] + (array)$user->mOptions;
$fields = array(
'user_id' => $seqVal,
'user_name' => $name,
- 'user_password' => $user->mPassword,
- 'user_newpassword' => $user->mNewpassword,
+ 'user_password' => $user->mPassword->toString(),
+ 'user_newpassword' => $user->mNewpassword->toString(),
'user_newpass_time' => $dbw->timestampOrNull( $user->mNewpassTime ),
'user_email' => $user->mEmail,
'user_email_authenticated' => $dbw->timestampOrNull( $user->mEmailAuthenticated ),
*/
public function addToDatabase() {
$this->load();
+ $this->loadPasswords();
if ( !$this->mToken ) {
$this->setToken(); // init token
}
array(
'user_id' => $seqVal,
'user_name' => $this->mName,
- 'user_password' => $this->mPassword,
- 'user_newpassword' => $this->mNewpassword,
+ 'user_password' => $this->mPassword->toString(),
+ 'user_newpassword' => $this->mNewpassword->toString(),
'user_newpass_time' => $dbw->timestampOrNull( $this->mNewpassTime ),
'user_email' => $this->mEmail,
'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
*/
public function checkPassword( $password ) {
global $wgAuth, $wgLegacyEncoding;
- $this->load();
+ $this->loadPasswords();
// Certain authentication plugins do NOT want to save
// domain passwords in a mysql database, so we should
// Auth plugin doesn't allow local authentication for this user name
return false;
}
- if ( self::comparePasswords( $this->mPassword, $password, $this->mId ) ) {
- return true;
- } elseif ( $wgLegacyEncoding ) {
- // Some wikis were converted from ISO 8859-1 to UTF-8, the passwords can't be converted
- // Check for this with iconv
- $cp1252Password = iconv( 'UTF-8', 'WINDOWS-1252//TRANSLIT', $password );
- if ( $cp1252Password != $password
- && self::comparePasswords( $this->mPassword, $cp1252Password, $this->mId )
- ) {
- return true;
+
+ $passwordFactory = self::getPasswordFactory();
+ if ( !$this->mPassword->equals( $password ) ) {
+ if ( $wgLegacyEncoding ) {
+ // Some wikis were converted from ISO 8859-1 to UTF-8, the passwords can't be converted
+ // Check for this with iconv
+ $cp1252Password = iconv( 'UTF-8', 'WINDOWS-1252//TRANSLIT', $password );
+ if ( $cp1252Password === $password || !$this->mPassword->equals( $cp1252Password ) ) {
+ return false;
+ }
+ } else {
+ return false;
}
}
- return false;
+
+ if ( $passwordFactory->needsUpdate( $this->mPassword ) ) {
+ $this->mPassword = $passwordFactory->newFromPlaintext( $password );
+ $this->saveSettings();
+ }
+
+ return true;
}
/**
global $wgNewPasswordExpiry;
$this->load();
- if ( self::comparePasswords( $this->mNewpassword, $plaintext, $this->getId() ) ) {
+ if ( $this->mNewpassword->equals( $plaintext ) ) {
if ( is_null( $this->mNewpassTime ) ) {
return true;
}
return $msg->isBlank() ? $right : $msg->text();
}
- /**
- * Make an old-style password hash
- *
- * @param string $password Plain-text password
- * @param string $userId User ID
- * @return string Password hash
- */
- public static function oldCrypt( $password, $userId ) {
- global $wgPasswordSalt;
- if ( $wgPasswordSalt ) {
- return md5( $userId . '-' . md5( $password ) );
- } else {
- return md5( $password );
- }
- }
-
/**
* Make a new-style password hash
*
* @param bool|string $salt Optional salt, may be random or the user ID.
* If unspecified or false, will generate one automatically
* @return string Password hash
+ * @deprecated since 1.23, use Password class
*/
public static function crypt( $password, $salt = false ) {
- global $wgPasswordSalt;
-
- $hash = '';
- if ( !wfRunHooks( 'UserCryptPassword', array( &$password, &$salt, &$wgPasswordSalt, &$hash ) ) ) {
- return $hash;
- }
-
- if ( $wgPasswordSalt ) {
- if ( $salt === false ) {
- $salt = MWCryptRand::generateHex( 8 );
- }
- return ':B:' . $salt . ':' . md5( $salt . '-' . md5( $password ) );
- } else {
- return ':A:' . md5( $password );
- }
+ wfDeprecated( __METHOD__, '1.23' );
+ $hash = self::getPasswordFactory()->newFromPlaintext( $password );
+ return $hash->toString();
}
/**
* @param string|bool $userId User ID for old-style password salt
*
* @return bool
+ * @deprecated since 1.23, use Password class
*/
public static function comparePasswords( $hash, $password, $userId = false ) {
- $type = substr( $hash, 0, 3 );
-
- $result = false;
- if ( !wfRunHooks( 'UserComparePasswords', array( &$hash, &$password, &$userId, &$result ) ) ) {
- return $result;
+ wfDeprecated( __METHOD__, '1.23' );
+
+ // Check for *really* old password hashes that don't even have a type
+ // The old hash format was just an md5 hex hash, with no type information
+ if ( preg_match( '/^[0-9a-f]{32}$/', $hash ) ) {
+ global $wgPasswordSalt;
+ if ( $wgPasswordSalt ) {
+ $password = ":B:{$userId}:{$hash}";
+ } else {
+ $password = ":A:{$hash}";
+ }
}
- if ( $type == ':A:' ) {
- // Unsalted
- return md5( $password ) === substr( $hash, 3 );
- } elseif ( $type == ':B:' ) {
- // Salted
- list( $salt, $realHash ) = explode( ':', substr( $hash, 3 ), 2 );
- return md5( $salt . '-' . md5( $password ) ) === $realHash;
- } else {
- // Old-style
- return self::oldCrypt( $password, $userId ) === $hash;
- }
+ $hash = self::getPasswordFactory()->newFromCiphertext( $hash );
+ return $hash->equals( $password );
}
/**
$dbw->insert( 'user_properties', $insert_rows, __METHOD__, array( 'IGNORE' ) );
}
+ /**
+ * Lazily instantiate and return a factory object for making passwords
+ *
+ * @return PasswordFactory
+ */
+ public static function getPasswordFactory() {
+ if ( self::$mPasswordFactory === null ) {
+ self::$mPasswordFactory = new PasswordFactory();
+ self::$mPasswordFactory->init( RequestContext::getMain()->getConfig() );
+ }
+
+ return self::$mPasswordFactory;
+ }
+
/**
* Provide an array of HTML5 attributes to put on an input element
* intended for the user to enter a new password. This may include
'user_id',
'user_name',
'user_real_name',
- 'user_password',
- 'user_newpassword',
- 'user_newpass_time',
'user_email',
'user_touched',
'user_token',
'user_email_authenticated',
'user_email_token',
'user_email_token_expires',
- 'user_password_expires',
'user_registration',
'user_editcount',
);
return true;
}
- /**
- * Get an associative array containing information about a file in the local filesystem.
- *
- * @param string $path Absolute local filesystem path
- * @param string|bool $ext The file extension, or true to extract it from
- * the filename. Set it to false to ignore the extension.
- *
- * @return array
- * @deprecated since 1.19
- */
- static function getPropsFromPath( $path, $ext = true ) {
- wfDebug( __METHOD__ . ": Getting file info for $path\n" );
- wfDeprecated( __METHOD__, '1.19' );
-
- $fsFile = new FSFile( $path );
-
- return $fsFile->getProps();
- }
-
- /**
- * Get a SHA-1 hash of a file in the local filesystem, in base-36 lower case
- * encoding, zero padded to 31 digits.
- *
- * 160 log 2 / log 36 = 30.95, so the 160-bit hash fills 31 digits in base 36
- * fairly neatly.
- *
- * @param string $path
- * @return bool|string False on failure
- * @deprecated since 1.19
- */
- static function sha1Base36( $path ) {
- wfDeprecated( __METHOD__, '1.19' );
-
- $fsFile = new FSFile( $path );
-
- return $fsFile->getSha1Base36();
- }
-
/**
* @return array HTTP header name/value map to use for HEAD/GET request responses
*/
"config-header-sqlite": "এসকিউলাইট সেটিংস",
"config-header-oracle": "ওরাকল সেটিংস",
"config-invalid-db-type": "ডেটাবেজের ধরন অগ্রহযোগ্য",
- "config-missing-db-name": "আপনাকে অবশ্যই \"ডেটাবেজ নাম\"-এর জন্য একটি মান প্রবেশ করাতে হবে",
- "config-missing-db-host": "আপনাকে অবশ্যই \"ডেটাবেজ হোস্ট\"-এর জন্য একটি মান প্রবেশ করাতে হবে",
- "config-missing-db-server-oracle": "আপনাকে অবশ্যই \"ডেটাবেজ টিএনএস\"-এর জন্য একটি মান প্রবেশ করাতে হবে",
+ "config-missing-db-name": "আপনাকে অবশ্যই \"{{int:config-db-name}}\"-এর জন্য একটি মান প্রবেশ করাতে হবে।",
+ "config-missing-db-host": "আপনাকে অবশ্যই \"{{int:config-db-host}}\"-এর জন্য একটি মান প্রবেশ করাতে হবে।",
+ "config-missing-db-server-oracle": "আপনাকে অবশ্যই \"{{int:config-db-host-oracle}}\"-এর জন্য একটি মান প্রবেশ করাতে হবে।",
"config-connection-error": "$1।\n\n\nদয়া করে প্রস্তাবকারী, ব্যবহারকারী নাম ও শব্দচাবি দেখুন এবং পুনরায় চেষ্টা করুন।",
"config-mysql-engine": "সংরক্ষণ ইঞ্জিন:",
"config-mysql-innodb": "ইনোডিবি",
"config-extensions": "Astennoù",
"config-extensions-help": "N'eo ket bet detektet an astennoù rollet a-us en ho kavlec'h <code>./astennoù</code>.\n\nMarteze e vo ezhomm kefluniañ pelloc'h met gallout a rit o gweredekaat bremañ.",
"config-skins": "Gwiskadurioù",
+ "config-skins-use-as-default": "Implijout ar gwiskadur-mañ dre ziouer",
+ "config-skins-must-enable-default": "Ar gwiskadur dre ziouer dibabet a rank bezañ gweredekaet.",
"config-install-alreadydone": "'''Diwallit''': Staliet hoc'h eus MediaWiki dija war a seblant hag emaoc'h o klask e staliañ c'hoazh.\nKit d'ar bajenn war-lerc'h, mar plij.",
"config-install-begin": "Pa vo bet pouezet ganeoc'h war \"{{int:config-continue}}\" e krogo staliadur MediaWiki.\nPouezit war \"{{int:config-back}}\" mar fell deoc'h cheñch tra pe dra.",
"config-install-step-done": "graet",
"config-enable-email": "Латае дӀайохьуьйту e-mail",
"config-upload-deleted": "ДӀаяхна файлийн директори:",
"config-cc-again": "Хьаржа кхин цӀа…",
+ "config-skins": "Кечяран тема",
+ "config-skins-use-as-default": "ХӀара тема Ӏад йитарца лелае",
+ "config-skins-must-enable-some": "Ахьа цхьаъ мукъа тема латина йита езаш ю.",
+ "config-skins-must-enable-default": "Ӏад йитарца йолу тема латина хила еза.",
"config-install-user": "Декъашхочун хаамийн база кхоллар",
"config-install-user-alreadyexists": "Декъашхо «$1» хӀинцале волуш ву",
"config-install-user-create-failed": "Декъашхо «$1» кхолла цаделира: $2",
"config-outdated-sqlite": "''' هشدار:''' شما اسکیولایت $1 دارید، که پایینتر از حداقل نسخهٔ $2 مورد نیاز است.اسکیولایت در دسترس نخواهد بود.",
"config-no-fts3": "'''هشدار:''' اسکیولایت بدون [//sqlite.org/fts3.html FTS3 module] تهیه شدهاست ، جستجوی ویژگیها در این بخش پیشین در دسترس نخواهدبود.",
"config-register-globals-error": "<strong>خطا: پیاچپی<code>[http://php.net/register_globals register_globals]</code> گزینه فعال است.\nبرای ادامه نصب باید غیر فعال باشد.</strong>\n[Https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] را برای کمک در مورد نحوه انجام این کار ببینید.",
+ "config-magic-quotes-gpc": "<strong>هشدار مهم: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc] فعال شدهاست!</strong>\nاین گزینه اطلاعات داده شده به رایانه را به طور غیرقابل پیشبینی از بین میبرد.\nشما نمیتوانید مدیاویکی را نصب یا استفاده کنید مگر اینکه این گزینه غیرفعال باشد.",
"config-magic-quotes-runtime": "'''مخرب: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] فعال است.\nاین گزینه اطلاعات داده شده به رایانه را به طور غیرقابل پیشبینی از بین میبرد.\nشما نمیتوانید مدیاویکی را نصب یا استفاده کنید مگر اینکه این گزینه غیرفعال باشد.",
"config-magic-quotes-sybase": "'''مخرب: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] فعال است.\nاین گزینه اطلاعات داده شده به رایانه را به طور غیرقابل پیشبینی از بین میبرد.\nشما نمیتوانید مدیاویکی را نصب یا استفاده کنید مگر اینکه این گزینه غیرفعال باشد.",
"config-mbstring": "''' مخرب:[http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] فعال است.\nاین گزینه باعث ایجاد خطا میشود و ممکن است اطلاعات را به طور غیرقابل پیشبینی از بین ببرد.\nشما نمیتوانید مدیاویکی را نصب یا استفاده کنید مگر اینکه این گزینه غیرفعال باشد.",
"config-license-cc-by-nc-sa": "اشتراک گذاری یکجور استناد رایج سازندهٔ غیر تجاری",
"config-license-cc-0": "مبداء عوام سازنده (حیطهٔ عمومی)",
"config-license-gfdl": "مجوز اسنادومدارک آزاد جیانیو ۱.۳ یا بالاتر",
- "config-license-pd": "دامنه عمومی",
+ "config-license-pd": "مالکیت عمومی",
"config-license-cc-choose": "انتخاب یک مجوز سفارشی عوام خلاق",
"config-license-help": "بسیاری از وبگاهها ویرایشهای ها را با [http://freedomdefined.org/Definition اجازهنامهٔ آزاد] منتشر میکنند.\nاین کار به داشتن حس مالکیت جمعی کمک میکند و ویرایشهای طولانی مدت را اشاعه میدهد.\nاین برای ویکیهای خصوصی یا سازمانی الزامی نیست.\n\nاگر شما میخواهید از متون ویکیپدیا استفاده کنید، یا اینکه به ویکیپدیا اجازه دهید از متون شما استفاده کند باید متون خود را با <strong>{{int:config-license-cc-by-sa}}</strong> منتشر کنید.\n\nویکیپدیا در گذشته از اجازهنامهٔ دادههای آزاد گنو استفاده میکرد.\nاین اجازهنامه مورد قبول است، ولی فهم آن آسان نیست.\nهمچنین استفادهٔ دوباره از متون تحت اجازهنامهٔ دادههای آزاد گنو به سختی انجام میگیرد.",
"config-email-settings": "تنظیمات رایانامه",
--- /dev/null
+<?php
+/**
+ * Implements the BcryptPassword class for the MediaWiki software.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * A Bcrypt-hashed password
+ *
+ * This is a computationally complex password hash for use in modern applications.
+ * The number of rounds can be configured by $wgPasswordCost.
+ *
+ * @since 1.24
+ */
+class BcryptPassword extends ParameterizedPassword {
+ protected function getDefaultParams() {
+ return array(
+ 'rounds' => $this->config['cost'],
+ );
+ }
+
+ protected function getDelimiter() {
+ return '$';
+ }
+
+ protected function parseHash( $hash ) {
+ parent::parseHash( $hash );
+
+ $this->params['rounds'] = (int)$this->params['rounds'];
+ }
+
+ /**
+ * @param string $password Password to encrypt
+ *
+ * @throws PasswordError If bcrypt has an unknown error
+ * @throws MWException If bcrypt is not supported by PHP
+ */
+ public function crypt( $password ) {
+ if ( !defined( 'CRYPT_BLOWFISH' ) ) {
+ throw new MWException( 'Bcrypt is not supported.' );
+ }
+
+ // Either use existing hash or make a new salt
+ // Bcrypt expects 22 characters of base64-encoded salt
+ // Note: bcrypt does not use MIME base64. It uses its own base64 without any '=' padding.
+ // It expects a 128 bit salt, so it will ignore anything after the first 128 bits
+ if ( !isset( $this->args[0] ) ) {
+ $this->args[] = substr(
+ // Replace + with ., because bcrypt uses a non-MIME base64 format
+ strtr(
+ // Random base64 encoded string
+ base64_encode( MWCryptRand::generate( 16, true ) ),
+ '+', '.'
+ ),
+ 0, 22
+ );
+ }
+
+ $hash = crypt( $password,
+ sprintf( '$2y$%02d$%s', (int)$this->params['rounds'], $this->args[0] ) );
+
+ if ( !is_string( $hash ) || strlen( $hash ) <= 13 ) {
+ throw new PasswordError( 'Error when hashing password.' );
+ }
+
+ // Strip the $2y$
+ $parts = explode( $this->getDelimiter(), substr( $hash, 4 ) );
+ $this->params['rounds'] = (int)$parts[0];
+ $this->args[0] = substr( $parts[1], 0, 22 );
+ $this->hash = substr( $parts[1], 22 );
+ }
+}
--- /dev/null
+<?php
+/**
+ * Implements the EncryptedPassword class for the MediaWiki software.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Helper class for passwords that use another password hash underneath it
+ * and encrypts that hash with a configured secret.
+ *
+ * @since 1.24
+ */
+class EncryptedPassword extends ParameterizedPassword {
+ protected function getDelimiter() {
+ return ':';
+ }
+
+ protected function getDefaultParams() {
+ return array(
+ 'cipher' => $this->config['cipher'],
+ 'secret' => count( $this->config['secrets'] ) - 1
+ );
+ }
+
+ public function crypt( $password ) {
+ $secret = $this->config['secrets'][$this->params['secret']];
+
+ if ( $this->hash ) {
+ $underlyingPassword = $this->factory->newFromCiphertext( openssl_decrypt(
+ base64_decode( $this->hash ), $this->params['cipher'],
+ $secret, 0, base64_decode( $this->args[0] )
+ ) );
+ } else {
+ $underlyingPassword = $this->factory->newFromType( $this->config['underlying'], $this->config );
+ }
+
+ $underlyingPassword->crypt( $password );
+ $iv = MWCryptRand::generate( openssl_cipher_iv_length( $this->params['cipher'] ), true );
+
+ $this->hash = openssl_encrypt(
+ $underlyingPassword->toString(), $this->params['cipher'], $secret, 0, $iv );
+ $this->args = array( base64_encode( $iv ) );
+ }
+
+ /**
+ * Updates the underlying hash by encrypting it with the newest secret.
+ *
+ * @throws MWException If the configuration is not valid
+ * @return bool True if the password was updated
+ */
+ public function update() {
+ if ( count( $this->args ) != 2 || $this->params == $this->getDefaultParams() ) {
+ // Hash does not need updating
+ return false;
+ }
+
+ // Decrypt the underlying hash
+ $underlyingHash = openssl_decrypt(
+ base64_decode( $this->args[1] ),
+ $this->params['cipher'],
+ $this->config['secrets'][$this->params['secret']],
+ 0,
+ base64_decode( $this->args[0] )
+ );
+
+ // Reset the params
+ $this->params = $this->getDefaultParams();
+
+ // Check the key size with the new params
+ $iv = MWCryptRand::generate( openssl_cipher_iv_length( $this->params['cipher'] ), true );
+ $this->hash = base64_encode( openssl_encrypt(
+ $underlyingHash,
+ $this->params['cipher'],
+ $this->config['secrets'][$this->params['secret']],
+ 0,
+ $iv
+ ) );
+ $this->args = array( base64_encode( $iv ) );
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Implements the InvalidPassword class for the MediaWiki software.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Represents an invalid password hash. It is represented as the empty string (i.e.,
+ * a password hash with no type).
+ *
+ * No two invalid passwords are equal. Comparing anything to an invalid password will
+ * return false.
+ *
+ * @since 1.24
+ */
+class InvalidPassword extends Password {
+ public function crypt( $plaintext ) {
+ }
+
+ public function toString() {
+ return '';
+ }
+
+ public function equals( $other ) {
+ return false;
+ }
+
+ public function needsUpdate() {
+ return false;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Implements the LayeredParameterizedPassword class for the MediaWiki software.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * This password hash type layers one or more parameterized password types
+ * on top of each other.
+ *
+ * The underlying types must be parameterized. This wrapping type accumulates
+ * all the parameters and arguments from each hash and then passes the hash of
+ * the last layer as the password for the next layer.
+ *
+ * @since 1.24
+ */
+class LayeredParameterizedPassword extends ParameterizedPassword {
+ protected function getDelimiter() {
+ return '!';
+ }
+
+ protected function getDefaultParams() {
+ $params = array();
+
+ foreach ( $this->config['types'] as $type ) {
+ $passObj = $this->factory->newFromType( $type );
+
+ if ( !$passObj instanceof ParameterizedPassword ) {
+ throw new MWException( 'Underlying type must be a parameterized password.' );
+ } elseif ( $passObj->getDelimiter() === $this->getDelimiter() ) {
+ throw new MWException( 'Underlying type cannot use same delimiter as encapsulating type.' );
+ }
+
+ $params[] = implode( $passObj->getDelimiter(), $passObj->getDefaultParams() );
+ }
+
+ return $params;
+ }
+
+ public function crypt( $password ) {
+ $lastHash = $password;
+ foreach ( $this->config['types'] as $i => $type ) {
+ // Construct pseudo-hash based on params and arguments
+ /** @var ParameterizedPassword $passObj */
+ $passObj = $this->factory->newFromType( $type );
+
+ $params = '';
+ $args = '';
+ if ( $this->params[$i] !== '' ) {
+ $params = $this->params[$i] . $passObj->getDelimiter();
+ }
+ if ( isset( $this->args[$i] ) && $this->args[$i] !== '' ) {
+ $args = $this->args[$i] . $passObj->getDelimiter();
+ }
+ $existingHash = ":$type:" . $params . $args . $this->hash;
+
+ // Hash the last hash with the next type in the layer
+ $passObj = $this->factory->newFromCiphertext( $existingHash );
+ $passObj->crypt( $lastHash );
+
+ // Move over the params and args
+ $this->params[$i] = implode( $passObj->getDelimiter(), $passObj->params );
+ $this->args[$i] = implode( $passObj->getDelimiter(), $passObj->args );
+ $lastHash = $passObj->hash;
+ }
+
+ $this->hash = $lastHash;
+ }
+
+ /**
+ * Finish the hashing of a partially hashed layered hash
+ *
+ * Given a password hash that is hashed using the first layer of this object's
+ * configuration, perform the remaining layers of password hashing in order to
+ * get an updated hash with all the layers.
+ *
+ * @param ParameterizedPassword $passObj Password hash of the first layer
+ *
+ * @throws MWException If the first parameter is not of the correct type
+ */
+ public function partialCrypt( ParameterizedPassword $passObj ) {
+ $type = $passObj->config['type'];
+ if ( $type !== $this->config['types'][0] ) {
+ throw new MWException( 'Only a hash in the first layer can be finished.' );
+ }
+
+ // Gather info from the existing hash
+ $this->params[0] = implode( $passObj->getDelimiter(), $passObj->params );
+ $this->args[0] = implode( $passObj->getDelimiter(), $passObj->args );
+ $lastHash = $passObj->hash;
+
+ // Layer the remaining types
+ foreach ( $this->config['types'] as $i => $type ) {
+ if ( $i == 0 ) {
+ continue;
+ };
+
+ // Construct pseudo-hash based on params and arguments
+ /** @var ParameterizedPassword $passObj */
+ $passObj = $this->factory->newFromType( $type );
+
+ $params = '';
+ $args = '';
+ if ( $this->params[$i] !== '' ) {
+ $params = $this->params[$i] . $passObj->getDelimiter();
+ }
+ if ( isset( $this->args[$i] ) && $this->args[$i] !== '' ) {
+ $args = $this->args[$i] . $passObj->getDelimiter();
+ }
+ $existingHash = ":$type:" . $params . $args . $this->hash;
+
+ // Hash the last hash with the next type in the layer
+ $passObj = $this->factory->newFromCiphertext( $existingHash );
+ $passObj->crypt( $lastHash );
+
+ // Move over the params and args
+ $this->params[$i] = implode( $passObj->getDelimiter(), $passObj->params );
+ $this->args[$i] = implode( $passObj->getDelimiter(), $passObj->args );
+ $lastHash = $passObj->hash;
+ }
+
+ $this->hash = $lastHash;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Implements the MWOldPassword class for the MediaWiki software.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * The old style of MediaWiki password hashing. It involves
+ * running MD5 on the password.
+ *
+ * @since 1.24
+ */
+class MWOldPassword extends ParameterizedPassword {
+ protected function getDefaultParams() {
+ return array();
+ }
+
+ protected function getDelimiter() {
+ return ':';
+ }
+
+ public function crypt( $plaintext ) {
+ global $wgPasswordSalt;
+
+ if ( $wgPasswordSalt && count( $this->args ) == 1 ) {
+ $this->hash = md5( $this->args[0] . '-' . md5( $plaintext ) );
+ } else {
+ $this->args = array();
+ $this->hash = md5( $plaintext );
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Implements the BcryptPassword class for the MediaWiki software.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * The old style of MediaWiki password hashing, with a salt. It involves
+ * running MD5 on the password, and then running MD5 on the salt concatenated
+ * with the first hash.
+ *
+ * @since 1.24
+ */
+class MWSaltedPassword extends ParameterizedPassword {
+ protected function getDefaultParams() {
+ return array();
+ }
+
+ protected function getDelimiter() {
+ return ':';
+ }
+
+ public function crypt( $plaintext ) {
+ if ( count( $this->args ) == 0 ) {
+ $this->args[] = MWCryptRand::generateHex( 8 );
+ }
+
+ $this->hash = md5( $this->args[0] . '-' . md5( $plaintext ) );
+ }
+}
--- /dev/null
+<?php
+/**
+ * Implements the ParameterizedPassword class for the MediaWiki software.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Helper class for password hash types that have a delimited set of parameters
+ * inside of the hash.
+ *
+ * All passwords are in the form of :<TYPE>:... as explained in the main Password
+ * class. This class is for hashes in the form of :<TYPE>:<PARAM1>:<PARAM2>:... where
+ * <PARAM1>, <PARAM2>, etc. are parameters that determine how the password was hashed.
+ * Of course, the internal delimiter (which is : by convention and default), can be
+ * changed by overriding the ParameterizedPassword::getDelimiter() function.
+ *
+ * This class requires overriding an additional function: ParameterizedPassword::getDefaultParams().
+ * See the function description for more details on the implementation.
+ *
+ * @since 1.24
+ */
+abstract class ParameterizedPassword extends Password {
+ /**
+ * Named parameters that have default values for this password type
+ * @var array
+ */
+ protected $params = array();
+
+ /**
+ * Extra arguments that were found in the hash. This may or may not make
+ * the hash invalid.
+ * @var array
+ */
+ protected $args = array();
+
+ protected function parseHash( $hash ) {
+ parent::parseHash( $hash );
+
+ if ( $hash === null ) {
+ $this->params = $this->getDefaultParams();
+ return;
+ }
+
+ $parts = explode( $this->getDelimiter(), $hash );
+ $paramKeys = array_keys( $this->getDefaultParams() );
+
+ if ( count( $parts ) < count( $paramKeys ) ) {
+ throw new PasswordError( 'Hash is missing required parameters.' );
+ }
+
+ if ( $paramKeys ) {
+ $this->args = array_splice( $parts, count( $paramKeys ) );
+ $this->params = array_combine( $paramKeys, $parts );
+ } else {
+ $this->args = $parts;
+ }
+
+ if ( $this->args ) {
+ $this->hash = array_pop( $this->args );
+ } else {
+ $this->hash = null;
+ }
+ }
+
+ public function needsUpdate() {
+ return parent::needsUpdate() || $this->params !== $this->getDefaultParams();
+ }
+
+ public function toString() {
+ return
+ ':' . $this->config['type'] . ':' .
+ implode( $this->getDelimiter(), array_merge( $this->params, $this->args ) ) .
+ $this->getDelimiter() . $this->hash;
+ }
+
+ /**
+ * Returns the delimiter for the parameters inside the hash
+ *
+ * @return string
+ */
+ abstract protected function getDelimiter();
+
+ /**
+ * Return an ordered array of default parameters for this password hash
+ *
+ * The keys should be the parameter names and the values should be the default
+ * values. Additionally, the order of the array should be the order in which they
+ * appear in the hash.
+ *
+ * When parsing a password hash, the constructor will split the hash based on
+ * the delimiter, and consume as many parts as it can, matching each to a parameter
+ * in this list. Once all the parameters have been filled, all remaining parts will
+ * be considered extra arguments, except, of course, for the very last part, which
+ * is the hash itself.
+ *
+ * @return array
+ */
+ abstract protected function getDefaultParams();
+}
--- /dev/null
+<?php
+/**
+ * Implements the Password class for the MediaWiki software.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Represents a password hash for use in authentication
+ *
+ * Note: All password types are transparently prefixed with :<TYPE>:, where <TYPE>
+ * is the registered type of the hash. This prefix is stripped in the constructor
+ * and is added back in the toString() function.
+ *
+ * When inheriting this class, there are a couple of expectations
+ * to be fulfilled:
+ * * If Password::toString() is called on an object, and the result is passed back in
+ * to PasswordFactory::newFromCiphertext(), the result will be identical to the original.
+ * * The string representations of two Password objects are equal only if
+ * the original plaintext passwords match. In other words, if the toString() result of
+ * two objects match, the passwords are the same, and the user will be logged in.
+ * Since the string representation of a hash includes its type name (@see Password::toString),
+ * this property is preserved across all classes that inherit Password.
+ * If a hashing scheme does not fulfill this expectation, it must make sure to override the
+ * Password::equals() function and use custom comparison logic. However, this is not
+ * recommended unless absolutely required by the hashing mechanism.
+ * With these two points in mind, when creating a new Password sub-class, there are some functions
+ * you have to override (because they are abstract) and others that you may want to override.
+ *
+ * The abstract functions that must be overridden are:
+ * * Password::crypt(), which takes a plaintext password and hashes it into a string hash suitable
+ * for being passed to the constructor of that class, and then stores that hash (and whatever
+ * other data) into the internal state of the object.
+ * The functions that can optionally be overridden are:
+ * * Password::parseHash(), which can be useful to override if you need to extract values from or
+ * otherwise parse a password hash when it's passed to the constructor.
+ * * Password::needsUpdate(), which can be useful if a specific password hash has different
+ * logic for when the hash needs to be updated.
+ * * Password::toString(), which can be useful if the hash was changed in the constructor and
+ * needs to be re-assembled before being returned as a string. This function is expected to add
+ * the type back on to the hash, so make sure to do that if you override the function.
+ * * Password::equals() - This function compares two Password objects to see if they are equal.
+ * The default is to just do a timing-safe string comparison on the $this->hash values.
+ *
+ * After creating a new password hash type, it can be registered using the static
+ * Password::register() method. The default type is set using the Password::setDefaultType() type.
+ * Types must be registered before they can be set as the default.
+ *
+ * @since 1.24
+ */
+abstract class Password {
+ /**
+ * @var PasswordFactory Factory that created the object
+ */
+ protected $factory;
+
+ /**
+ * String representation of the hash without the type
+ * @var string
+ */
+ protected $hash;
+
+ /**
+ * Array of configuration variables injected from the constructor
+ * @var array
+ */
+ protected $config;
+
+ /**
+ * Construct the Password object using a string hash
+ *
+ * It is strongly recommended not to call this function directly unless you
+ * have a reason to. Use the PasswordFactory class instead.
+ *
+ * @throws MWException If $config does not contain required parameters
+ *
+ * @param PasswordFactory $factory Factory object that created the password
+ * @param array $config Array of engine configuration options for hashing
+ * @param string|null $hash The raw hash, including the type
+ */
+ final public function __construct( PasswordFactory $factory, array $config, $hash = null ) {
+ if ( !isset( $config['type'] ) ) {
+ throw new MWException( 'Password configuration must contain a type name.' );
+ }
+ $this->config = $config;
+ $this->factory = $factory;
+
+ if ( $hash !== null && strlen( $hash ) >= 3 ) {
+ // Strip the type from the hash for parsing
+ $hash = substr( $hash, strpos( $hash, ':', 1 ) + 1 );
+ }
+
+ $this->hash = $hash;
+ $this->parseHash( $hash );
+ }
+
+ /**
+ * Get the type name of the password
+ *
+ * @return string Password type
+ */
+ final public function getType() {
+ return $this->config['type'];
+ }
+
+ /**
+ * Perform any parsing necessary on the hash to see if the hash is valid
+ * and/or to perform logic for seeing if the hash needs updating.
+ *
+ * @param string $hash The hash, with the :<TYPE>: prefix stripped
+ * @throws PasswordError If there is an error in parsing the hash
+ */
+ protected function parseHash( $hash ) {
+ }
+
+ /**
+ * Determine if the hash needs to be updated
+ *
+ * @return bool True if needs update, false otherwise
+ */
+ public function needsUpdate() {
+ }
+
+ /**
+ * Compare one Password object to this object
+ *
+ * By default, do a timing-safe string comparison on the result of
+ * Password::toString() for each object. This can be overridden to do
+ * custom comparison, but it is not recommended unless necessary.
+ *
+ * @param Password|string $other The other password
+ * @return bool True if equal, false otherwise
+ */
+ public function equals( $other ) {
+ if ( !$other instanceof self ) {
+ // No need to use the factory because we're definitely making
+ // an object of the same type.
+ $obj = clone $this;
+ $obj->crypt( $other );
+ $other = $obj;
+ }
+
+ return hash_equals( $this->toString(), $other->toString() );
+ }
+
+ /**
+ * Convert this hash to a string that can be stored in the database
+ *
+ * The resulting string should be considered the seralized representation
+ * of this hash, i.e., if the return value were recycled back into
+ * PasswordFactory::newFromCiphertext, the returned object would be equivalent to
+ * this; also, if two objects return the same value from this function, they
+ * are considered equivalent.
+ *
+ * @return string
+ */
+ public function toString() {
+ return ':' . $this->config['type'] . ':' . $this->hash;
+ }
+
+ /**
+ * Hash a password and store the result in this object
+ *
+ * The result of the password hash should be put into the internal
+ * state of the hash object.
+ *
+ * @param string $password Password to hash
+ * @throws PasswordError If an internal error occurs in hashing
+ */
+ abstract public function crypt( $password );
+}
--- /dev/null
+<?php
+/**
+ * Implements the Password class for the MediaWiki software.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Factory class for creating and checking Password objects
+ *
+ * @since 1.24
+ */
+final class PasswordFactory {
+ /**
+ * The default PasswordHash type
+ *
+*@var string
+ * @see PasswordFactory::setDefaultType
+ */
+ private $default = '';
+
+ /**
+ * Mapping of password types to classes
+ * @var array
+ * @see PasswordFactory::register
+ * @see Setup.php
+ */
+ private $types = array(
+ '' => array( 'type' => '', 'class' => 'InvalidPassword' ),
+ );
+
+ /**
+ * Register a new type of password hash
+ *
+ * @param string $type Unique type name for the hash
+ * @param array $config Array of configuration options
+ */
+ public function register( $type, array $config ) {
+ $config['type'] = $type;
+ $this->types[$type] = $config;
+ }
+
+ /**
+ * Set the default password type
+ *
+ * @throws InvalidArgumentException If the type is not registered
+ * @param string $type Password hash type
+ */
+ public function setDefaultType( $type ) {
+ if ( !isset( $this->types[$type] ) ) {
+ throw new InvalidArgumentException( "Invalid password type $type." );
+ }
+ $this->default = $type;
+ }
+
+ /**
+ * Initialize the internal static variables using the global variables
+ *
+ * @param Config $config Configuration object to load data from
+ */
+ public function init( Config $config ) {
+ foreach ( $config->get( 'PasswordConfig' ) as $type => $options ) {
+ $this->register( $type, $options );
+ }
+
+ $this->setDefaultType( $config->get( 'PasswordDefault' ) );
+ }
+
+ /**
+ * Get the list of types of passwords
+ *
+ * @return array
+ */
+ public function getTypes() {
+ return $this->types;
+ }
+
+ /**
+ * Create a new Hash object from an existing string hash
+ *
+ * Parse the type of a hash and create a new hash object based on the parsed type.
+ * Pass the raw hash to the constructor of the new object. Use InvalidPassword type
+ * if a null hash is given.
+ *
+ * @param string|null $hash Existing hash or null for an invalid password
+ * @return Password object
+ * @throws PasswordError if hash is invalid or type is not recognized
+ */
+ public function newFromCiphertext( $hash ) {
+ if ( $hash === null || $hash === false || $hash === '' ) {
+ return new InvalidPassword( $this, array( 'type' => '' ), null );
+ } elseif ( $hash[0] !== ':' ) {
+ throw new PasswordError( 'Invalid hash given' );
+ }
+
+ $type = substr( $hash, 1, strpos( $hash, ':', 1 ) - 1 );
+ if ( !isset( $this->types[$type] ) ) {
+ throw new PasswordError( "Unrecognized password hash type $type." );
+ }
+
+ $config = $this->types[$type];
+
+ return new $config['class']( $this, $config, $hash );
+ }
+
+ /**
+ * Make a new default password of the given type.
+ *
+ * @param string $type Existing type
+ * @return Password object
+ * @throws PasswordError if hash is invalid or type is not recognized
+ */
+ public function newFromType( $type ) {
+ if ( !isset( $this->types[$type] ) ) {
+ throw new PasswordError( "Unrecognized password hash type $type." );
+ }
+
+ $config = $this->types[$type];
+
+ return new $config['class']( $this, $config );
+ }
+
+ /**
+ * Create a new Hash object from a plaintext password
+ *
+ * If no existing object is given, make a new default object. If one is given, clone that
+ * object. Then pass the plaintext to Password::crypt().
+ *
+ * @param string $password Plaintext password
+ * @param Password|null $existing Optional existing hash to get options from
+ * @return Password object
+ */
+ public function newFromPlaintext( $password, Password $existing = null ) {
+ if ( $existing === null ) {
+ $config = $this->types[$this->default];
+ $obj = new $config['class']( $this, $config );
+ } else {
+ $obj = clone $existing;
+ }
+
+ $obj->crypt( $password );
+
+ return $obj;
+ }
+
+ /**
+ * Determine whether a password object needs updating
+ *
+ * Check whether the given password is of the default type. If it is,
+ * pass off further needsUpdate checks to Password::needsUpdate.
+ *
+ * @param Password $password
+ *
+ * @return bool True if needs update, false otherwise
+ */
+ public function needsUpdate( Password $password ) {
+ if ( $password->getType() !== $this->default ) {
+ return true;
+ } else {
+ return $password->needsUpdate();
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Implements the Pbkdf2Password class for the MediaWiki software.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * A PBKDF2-hashed password
+ *
+ * This is a computationally complex password hash for use in modern applications.
+ * The number of rounds can be configured by $wgPasswordConfig['pbkdf2']['cost'].
+ *
+ * @since 1.24
+ */
+class Pbkdf2Password extends ParameterizedPassword {
+ protected function getDefaultParams() {
+ return array(
+ 'algo' => $this->config['algo'],
+ 'rounds' => $this->config['cost'],
+ 'length' => $this->config['length']
+ );
+ }
+
+ protected function getDelimiter() {
+ return ':';
+ }
+
+ public function crypt( $password ) {
+ if ( count( $this->args ) == 0 ) {
+ $this->args[] = base64_encode( MWCryptRand::generate( 16, true ) );
+ }
+
+ if ( function_exists( 'hash_pbkdf2' ) ) {
+ $hash = hash_pbkdf2(
+ $this->params['algo'],
+ $password,
+ base64_decode( $this->args[0] ),
+ $this->params['rounds'],
+ $this->params['length'],
+ true
+ );
+ } else {
+ $hashLen = strlen( hash( $this->params['algo'], '', true ) );
+ $blockCount = ceil( $this->params['length'] / $hashLen );
+
+ $hash = '';
+ $salt = base64_decode( $this->args[0] );
+ for ( $i = 1; $i <= $blockCount; ++$i ) {
+ $roundTotal = $lastRound = hash_hmac(
+ $this->params['algo'],
+ $salt . pack( 'N', $i ),
+ $password,
+ true
+ );
+
+ for ( $j = 1; $j < $this->params['rounds']; ++$j ) {
+ $lastRound = hash_hmac( $this->params['algo'], $lastRound, $password, true );
+ $roundTotal ^= $lastRound;
+ }
+
+ $hash .= $roundTotal;
+ }
+
+ $hash = substr( $hash, 0, $this->params['length'] );
+ }
+
+ $this->hash = base64_encode( $hash );
+ }
+}
'\': expected ResourceLoaderModule or array (got: ' . gettype( $info ) . ')'
);
}
+
+ // Last-minute changes
+
+ // Apply custom skin-defined styles to existing modules.
+ if ( $this->isFileModule( $name ) ) {
+ global $wgResourceModuleSkinStyles;
+ foreach ( $wgResourceModuleSkinStyles as $skinName => $skinStyles ) {
+ // If this module already defines skinStyles for this skin, ignore $wgResourceModuleSkinStyles.
+ if ( isset( $this->moduleInfos[$name]['skinStyles'][$skinName] ) ) {
+ continue;
+ }
+
+ // If $name is preceded with a '+', the defined style files will be added to 'default'
+ // skinStyles, otherwise 'default' will be ignored as it normally would be.
+ if ( isset( $skinStyles[ $name ] ) ) {
+ $paths = (array)$skinStyles[ $name ];
+ $styleFiles = array();
+ } else if ( isset( $skinStyles[ '+' . $name ] ) ) {
+ $paths = (array)$skinStyles[ '+' . $name ];
+ $styleFiles = isset( $this->moduleInfos[$name]['skinStyles']['default'] ) ?
+ $this->moduleInfos[$name]['skinStyles']['default'] :
+ array();
+ } else {
+ continue;
+ }
+
+ // Add new file paths, remapping them to refer to our directories and not use settings
+ // from the module we're modifying. These can come from the base definition or be defined
+ // for each module.
+ list( $localBasePath, $remoteBasePath ) =
+ ResourceLoaderFileModule::extractBasePaths( $skinStyles );
+ list( $localBasePath, $remoteBasePath ) =
+ ResourceLoaderFileModule::extractBasePaths( $paths, $localBasePath, $remoteBasePath );
+
+ foreach ( $paths as $path ) {
+ $styleFiles[] = new ResourceLoaderFilePath( $path, $localBasePath, $remoteBasePath );
+ }
+
+ $this->moduleInfos[$name]['skinStyles'][$skinName] = $styleFiles;
+ }
+ }
}
wfProfileOut( __METHOD__ );
return $this->modules[$name];
}
+ /**
+ * Return whether the definition of a module corresponds to a simple ResourceLoaderFileModule.
+ *
+ * @param string $name Module name
+ * @return boolean
+ */
+ protected function isFileModule( $name ) {
+ if ( !isset( $this->moduleInfos[$name] ) ) {
+ return false;
+ }
+ $info = $this->moduleInfos[$name];
+ if ( isset( $info['object'] ) || isset( $info['class'] ) ) {
+ return false;
+ }
+ return true;
+ }
+
/**
* Get the list of sources.
*
* )
* @endcode
*/
- public function __construct( $options = array(), $localBasePath = null,
+ public function __construct(
+ $options = array(),
+ $localBasePath = null,
$remoteBasePath = null
) {
- global $IP, $wgScriptPath, $wgResourceBasePath;
- $this->localBasePath = $localBasePath === null ? $IP : $localBasePath;
- if ( $remoteBasePath !== null ) {
- $this->remoteBasePath = $remoteBasePath;
- } else {
- $this->remoteBasePath = $wgResourceBasePath === null ? $wgScriptPath : $wgResourceBasePath;
- }
-
- if ( isset( $options['remoteExtPath'] ) ) {
- global $wgExtensionAssetsPath;
- $this->remoteBasePath = $wgExtensionAssetsPath . '/' . $options['remoteExtPath'];
- }
-
- if ( isset( $options['remoteSkinPath'] ) ) {
- global $wgStylePath;
- $this->remoteBasePath = $wgStylePath . '/' . $options['remoteSkinPath'];
- }
+ // localBasePath and remoteBasePath both have unbelievably long fallback chains
+ // and need to be handled separately.
+ list( $this->localBasePath, $this->remoteBasePath ) =
+ self::extractBasePaths( $options, $localBasePath, $remoteBasePath );
+ // Extract, validate and normalise remaining options
foreach ( $options as $member => $option ) {
switch ( $member ) {
// Lists of file paths
// Single strings
case 'group':
case 'position':
- case 'localBasePath':
- case 'remoteBasePath':
case 'skipFunction':
$this->{$member} = (string)$option;
break;
break;
}
}
+ }
+
+ /**
+ * Extract a pair of local and remote base paths from module definition information.
+ * Implementation note: the amount of global state used in this function is staggering.
+ *
+ * @param array $options Module definition
+ * @param string $localBasePath Path to use if not provided in module definition. Defaults
+ * to $IP
+ * @param string $remoteBasePath Path to use if not provided in module definition. Defaults
+ * to $wgScriptPath
+ * @return array array( localBasePath, remoteBasePath )
+ */
+ public static function extractBasePaths(
+ $options = array(),
+ $localBasePath = null,
+ $remoteBasePath = null
+ ) {
+ global $IP, $wgScriptPath, $wgResourceBasePath;
+
+ // The different ways these checks are done, and their ordering, look very silly,
+ // but were preserved for backwards-compatibility just in case. Tread lightly.
+
+ $localBasePath = $localBasePath === null ? $IP : $localBasePath;
+ if ( $remoteBasePath !== null ) {
+ $remoteBasePath = $remoteBasePath;
+ } else {
+ $remoteBasePath = $wgResourceBasePath === null ? $wgScriptPath : $wgResourceBasePath;
+ }
+
+ if ( isset( $options['remoteExtPath'] ) ) {
+ global $wgExtensionAssetsPath;
+ $remoteBasePath = $wgExtensionAssetsPath . '/' . $options['remoteExtPath'];
+ }
+
+ if ( isset( $options['remoteSkinPath'] ) ) {
+ global $wgStylePath;
+ $remoteBasePath = $wgStylePath . '/' . $options['remoteSkinPath'];
+ }
+
+ if ( array_key_exists( 'localBasePath', $options ) ) {
+ $localBasePath = (string)$options['localBasePath'];
+ }
+
+ if ( array_key_exists( 'remoteBasePath', $options ) ) {
+ $remoteBasePath = (string)$options['remoteBasePath'];
+ }
+
// Make sure the remote base path is a complete valid URL,
// but possibly protocol-relative to avoid cache pollution
- $this->remoteBasePath = wfExpandUrl( $this->remoteBasePath, PROTO_RELATIVE );
+ $remoteBasePath = wfExpandUrl( $remoteBasePath, PROTO_RELATIVE );
+
+ return array( $localBasePath, $remoteBasePath );
}
/**
/* Protected Methods */
/**
- * @param string $path
+ * @param string|ResourceLoaderFilePath $path
* @return string
*/
protected function getLocalPath( $path ) {
+ if ( $path instanceof ResourceLoaderFilePath ) {
+ return $path->getLocalPath();
+ }
+
return "{$this->localBasePath}/$path";
}
/**
- * @param string $path
+ * @param string|ResourceLoaderFilePath $path
* @return string
*/
protected function getRemotePath( $path ) {
+ if ( $path instanceof ResourceLoaderFilePath ) {
+ return $path->getRemotePath();
+ }
+
return "{$this->remoteBasePath}/$path";
}
$files = array_merge( $files, $this->debugScripts );
}
- return array_unique( $files );
+ return array_unique( $files, SORT_REGULAR );
}
/**
return '';
}
$js = '';
- foreach ( array_unique( $scripts ) as $fileName ) {
+ foreach ( array_unique( $scripts, SORT_REGULAR ) as $fileName ) {
$localPath = $this->getLocalPath( $fileName );
if ( !file_exists( $localPath ) ) {
throw new MWException( __METHOD__ . ": script file not found: \"$localPath\"" );
return array();
}
foreach ( $styles as $media => $files ) {
- $uniqueFiles = array_unique( $files );
+ $uniqueFiles = array_unique( $files, SORT_REGULAR );
$styleFiles = array();
foreach ( $uniqueFiles as $file ) {
$styleFiles[] = $this->readStyleFile( $file, $flip );
*/
protected function readStyleFile( $path, $flip ) {
$localPath = $this->getLocalPath( $path );
+ $remotePath = $this->getRemotePath( $path );
if ( !file_exists( $localPath ) ) {
$msg = __METHOD__ . ": style file not found: \"$localPath\"";
wfDebugLog( 'resourceloader', $msg );
throw new MWException( $msg );
}
- if ( $this->getStyleSheetLang( $path ) === 'less' ) {
+ if ( $this->getStyleSheetLang( $localPath ) === 'less' ) {
$style = $this->compileLESSFile( $localPath );
$this->hasGeneratedStyles = true;
} else {
if ( $flip ) {
$style = CSSJanus::transform( $style, true, false );
}
- $dirname = dirname( $path );
- if ( $dirname == '.' ) {
- // If $path doesn't have a directory component, don't prepend a dot
- $dirname = '';
- }
- $dir = $this->getLocalPath( $dirname );
- $remoteDir = $this->getRemotePath( $dirname );
+ $localDir = dirname( $localPath );
+ $remoteDir = dirname( $remotePath );
// Get and register local file references
$this->localFileRefs = array_merge(
$this->localFileRefs,
- CSSMin::getLocalFileReferences( $style, $dir )
+ CSSMin::getLocalFileReferences( $style, $localDir )
);
return CSSMin::remap(
- $style, $dir, $remoteDir, true
+ $style, $localDir, $remoteDir, true
);
}
--- /dev/null
+<?php
+/**
+ * An object to represent a path to a JavaScript/CSS file, along with a remote
+ * and local base path, for use with ResourceLoaderFileModule.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * An object to represent a path to a JavaScript/CSS file, along with a remote
+ * and local base path, for use with ResourceLoaderFileModule.
+ */
+class ResourceLoaderFilePath {
+ /* Protected Members */
+
+ /** @var string Local base path */
+ protected $localBasePath;
+
+ /** @var string Remote base path */
+ protected $remoteBasePath;
+
+ /**
+ * @var string Path to the file */
+ protected $path;
+
+ /* Methods */
+
+ /**
+ * @param string $path Path to the file.
+ * @param string $localBasePath Base path to prepend when generating a local path.
+ * @param string $remoteBasePath Base path to prepend when generating a remote path.
+ */
+ public function __construct( $path, $localBasePath, $remoteBasePath ) {
+ $this->path = $path;
+ $this->localBasePath = $localBasePath;
+ $this->remoteBasePath = $remoteBasePath;
+ }
+
+ /**
+ * @return string
+ */
+ public function getLocalPath() {
+ return "{$this->localBasePath}/{$this->path}";
+ }
+
+ /**
+ * @return string
+ */
+ public function getRemotePath() {
+ return "{$this->remoteBasePath}/{$this->path}";
+ }
+
+ /**
+ * @return string
+ */
+ public function getPath() {
+ return $this->path;
+ }
+}
$count = 0;
foreach ( $this->getWatchlistInfo() as $namespace => $pages ) {
- if ( $namespace >= 0 ) {
- $fields['TitlesNs' . $namespace] = array(
- 'class' => 'EditWatchlistCheckboxSeriesField',
- 'options' => array(),
- 'section' => "ns$namespace",
- );
- }
+ $options = array();
foreach ( array_keys( $pages ) as $dbkey ) {
$title = Title::makeTitleSafe( $namespace, $dbkey );
if ( $this->checkTitle( $title, $namespace, $dbkey ) ) {
$text = $this->buildRemoveLine( $title );
- $fields['TitlesNs' . $namespace]['options'][$text] = $title->getPrefixedText();
+ $options[$text] = $title->getPrefixedText();
$count++;
}
}
+
+ // checkTitle can filter some options out, avoid empty sections
+ if ( count( $options ) > 0 ) {
+ $fields['TitlesNs' . $namespace] = array(
+ 'class' => 'EditWatchlistCheckboxSeriesField',
+ 'options' => $options,
+ 'section' => "ns$namespace",
+ );
+ }
}
$this->cleanupWatchlist();
"preview": "Папярэдні прагляд",
"showpreview": "Праглядзець",
"showdiff": "Паказаць зьмены",
+ "blankarticle": "<strong>Папярэджаньне:</strong> вы ствараеце пустую старонку.\nКалі вы націсьніце «{{int:savearticle}}» яшчэ раз, старонка будзе створаная без аніякага зьместу.",
"anoneditwarning": "'''Папярэджаньне:''' Вы не ўвайшлі ў сыстэму. Ваш IP-адрас будзе запісаны ў гісторыі гэтай старонкі.",
"anonpreviewwarning": "''Вы не ўвайшлі ў сыстэму. Падчас захаваньня Ваш IP-адрас будзе дададзены ў гісторыю рэдагаваньняў старонкі.''",
"missingsummary": "'''Напамін:''' Вы не пазначылі кароткае апісаньне зьменаў.\nКалі Вы націсьніце кнопку «Запісаць» яшчэ раз, Вашае рэдагаваньне будзе запісанае без апісаньня.",
"recentchanges-label-plusminus": "Памер старонкі зьмяніўся на такую колькасьць байтаў",
"recentchanges-legend-heading": "'''Легенда:'''",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (глядзіце таксама [[Special:NewPages|сьпіс новых старонак]])",
- "rcnotefrom": "Ніжэй знаходзяцца зьмены з <strong>$2</strong> (да <strong>$1</strong> на старонку).",
+ "rcnotefrom": "Ніжэй {{PLURAL:$5|знаходзіцца зьмена|знаходзяцца зьмены}} з <strong>$4 $3</strong> (да <strong>$1</strong> на старонку).",
"rclistfrom": "Паказаць зьмены з $2 $3",
"rcshowhideminor": "$1 дробныя праўкі",
"rcshowhideminor-show": "Паказаць",
"preview": "Перадпаказ",
"showpreview": "Як будзе",
"showdiff": "Розніца",
+ "blankarticle": "<strong>Увага:</strong> Вы ствараеце пустую старонку.\nКалі вы націсніце \"{{int:savearticle}}\" яшчэ раз, будзе створана старонка без аніякага зместу.",
"anoneditwarning": "Вы не ўвайшлі ў сістэму. Таму, калі вы запішаце старонку, у яе гісторыю трапіць ваш адрас IP.",
"anonpreviewwarning": "''Вы не прайшлі ідэнтыфікацыю Захаванне будзе запісана з вашым IP адрасам у гісторыі правак гэтай старонкі.''",
"missingsummary": "<strong>Нагадваем:</strong> вы не ўпісалі тлумачэння для сваёй праўкі. Калі націснуць \"{{int:savearticle}}\" яшчэ раз, праўка будзе замацавана без тлумачэння.",
"import-invalid-interwiki": "Немагчыма імпартаваць з гэтай вікі.",
"import-error-edit": "Старонка «$1» не была імпартавана, бо вам не дазволена яе правіць.",
"import-error-create": "Старонка «$1» не была імпартавана, бо вам не дазволена яе ствараць.",
- "import-error-interwiki": "Старонка «$1» не была імпартаваная, таму што гэтая назва зарэзерваваная для інтэрвікі.",
+ "import-error-interwiki": "Старонка «$1» не была імпартавана, таму што гэта назва зарэзервавана для інтэрвікі.",
"import-error-special": "Старонка «$1» не была імпартаваная, таму што яна належыць да спецыяльнай прасторы назваў, старонкі ў якой не дазволеныя.",
- "import-error-invalid": "Старонка «$1» не была імпартаваная з-за няслушнасці назвы.",
+ "import-error-invalid": "Старонка «$1» не была імпартавана, таму што назва, пад якую яна імпартуецца, недапушчальная на гэтай вікі.",
"import-error-unserialize": "Немагчыма дэсерыялізаваць версію $2 старонкі \"$1\". Меркавалася, што версія выкарыстоўвае мадэль змесціва $3, серыялізавана як $4.",
"import-error-bad-location": "Версія $2, якая выкарыстоўвае мадэль змесціва $3, не можа быць запісана на старонцы \"$1\" гэтай вікі, паколькі такая мадэль не падтрымліваецца на гэтай старонцы.",
"import-options-wrong": "{{PLURAL:$2|1=Няправільны параметр|Няправільныя параметры}}: <nowiki>$1</nowiki>",
"importlogpage": "Журнал імпартаванняў",
"importlogpagetext": "Адміністрацыйныя імпартаванні старонак з іншых вікі, разам з гісторыямі правак.",
"import-logentry-upload": "імпартавана [[$1]] праз файлавы ўклад",
- "import-logentry-upload-detail": "$1 {{PLURAL:$1|версія|версіі|версій}}",
+ "import-logentry-upload-detail": "$1 {{PLURAL:$1|версія|версіі|версій}} імпартавана",
"import-logentry-interwiki": "транс-вікавана $1",
- "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|версія|версіі|версій}} з $2",
+ "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|версія|версіі|версій}} імпартавана з $2",
"javascripttest": "JavaScript-тэсты",
"javascripttest-title": "Праводзіцца тэставанне $1",
"javascripttest-pagetext-noframework": "Гэта старонка зарэзервавана для запуску тэстаў JavaScript",
"autosumm-replace": "Замена старонкі на '$1'",
"autoredircomment": "Перасылае да [[$1]]",
"autosumm-new": "Новая старонка: '$1'",
+ "autosumm-newblank": "Створана пустая старонка",
"lag-warn-normal": "Змены, зробленыя менш за $1 {{PLURAL:$1|сек.|сек.}} таму назад, могуць не трапіць у гэты спіс.",
"lag-warn-high": "З прычыны моцных затрымак на серверы баз звестак, змены, зробленыя менш за $1 {{PLURAL:$1|сек.|сек.}} таму назад, могуць не трапіць у гэты спіс.",
"watchlistedit-normal-title": "Спіс назірання",
"importlogpage": "আমদানি লগ",
"importlogpagetext": "প্রশাসক কর্তৃক অন্যান্য উইকি থেকে সম্পাদনা ইতিহাসসহ পাতা আমদানি।",
"import-logentry-upload": "ফাইল আপলোডের মাধ্যমে [[$1]] আমদানি করা হয়েছে",
- "import-logentry-upload-detail": "$1 {{PLURAL:$1|টি সংশোধন|টি সংশোধন}}",
+ "import-logentry-upload-detail": "$1টি {{PLURAL:$1|সংশোধন}} আমদানি করা হয়েছে",
"import-logentry-interwiki": "$1 উইকি-স্থানান্তরিত",
- "import-logentry-interwiki-detail": "$2-à¦\8fর à¦\95রা $1 {{PLURAL:$1|সà¦\82শà§\8bধন|à¦\9fি সà¦\82শà§\8bধন}}",
+ "import-logentry-interwiki-detail": "$2-à¦\8fর থà§\87à¦\95à§\87 $1à¦\9fি {{PLURAL:$1|সà¦\82শà§\8bধন}} à¦\95রা হয়à§\87à¦\9bà§\87",
"javascripttest": "জাভাস্ক্রিপ্ট পরীক্ষা",
"javascripttest-title": "$1 পরীক্ষা চলছে",
"javascripttest-pagetext-noframework": "এই পাতাটি জাভাস্ক্রিপ্ট পরীক্ষার জন্য সংরক্ষিত।",
"autosumm-replace": "পাতাকে '$1' দিয়ে প্রতিস্থাপিত করা হল",
"autoredircomment": "[[$1]]-এ পুনর্নির্দেশ করা হল",
"autosumm-new": "$1 দিয়ে তৈরি পাতা",
+ "autosumm-newblank": "খালি পাতা তৈরি হয়েছে",
"size-bytes": "$1 বাইট",
"size-kilobytes": "$1 কিলোবাইট",
"size-megabytes": "$1 মেগাবাইট",
"powersearch-togglelabel": "Dibab :",
"powersearch-toggleall": "An holl",
"powersearch-togglenone": "Hini ebet",
+ "powersearch-remember": "Derc'hel soñj eus an diuzadenn evit klaskoù da zont",
"search-external": "Klask diavaez",
"searchdisabled": "<p>Diweredekaet eo bet an arc'hwel klask war an destenn a-bezh evit ur frapad rak ur samm re vras e oa evit ar servijer. Emichañs e vo tu d'e adlakaat pa vo ur servijer galloudusoc'h ganeomp. Da c'hortoz e c'hallit klask gant Google:</p>",
"search-error": "Ur fazi a zo bet e-ser klask : $1",
"wantedfiles": "Restroù a vank",
"wantedfiletext-cat": "Ober a reer gant ar restroù da-heul koulskoude n'eus ket anezho. Gallout a reer rollañ kavlec'hioù diavaez ha pa vefe anezho. <del>Barrennet</del> e vo an holl falspozitivoù-se. Ouzhpenn-se emañ renablet an holl bajennoù zo enno restroù n'eus ket anezho e [[:$1]].",
"wantedfiletext-nocat": "Ober a reer gant ar restroù da-heul koulskoude n'eus ket anezho. Gallout a reer rollañ kavlec'hioù diavaez ha pa vefe anezho. <del>Barrennet</del> e vo an holl falspozitivoù-se.",
+ "wantedfiletext-nocat-noforeign": "Implijet e vez ar restroù-mañ met n'eus ket anezho.",
"wantedtemplates": "Patromoù a vank",
"mostlinked": "Pajennoù dezho al liammoù niverusañ",
"mostlinkedcategories": "Rummadoù dezho al liammoù niverusañ",
"autosumm-replace": "Oc'h erlec'hiañ ar bajenn gant '$1'",
"autoredircomment": "Adkas war-du [[$1]]",
"autosumm-new": "Pajenn krouet gant : \"$1\"",
+ "autosumm-newblank": "Krouet eo bet ur bajenn c'houllo",
"size-bytes": "$1 o",
"size-kilobytes": "$1 Kio",
"size-megabytes": "$1 Mio",
"hidden-category-category": "Къайлаха йолу категореш",
"category-subcat-count": "{{PLURAL:$2|ХӀокху категори чохь ю хӀокхуьнан бухара категори.|ХӀокху категори чохь ю $1 {{PLURAL:$1|бухара категори|бухара категореш}} $2 массо нах.}}",
"category-subcat-count-limited": "ХӀокх категори чохь {{PLURAL:$1|бухар категори|$1 бухар категореш}} ю.",
- "category-article-count": "{{PLURAL:$2|ХӀокху категори чохь яц цхьа агӀо бе.|{{PLURAL:$1|Гойту $1 агӀо|Гойту $1 агӀонаш}} хӀокху категорешца кху $2.}}",
+ "category-article-count": "{{PLURAL:$2|ХӀокху категори чохь яц цхьа агӀо бе.|ХӀокху категори чохь ю $2 агӀо, царах агӀонгахь {{PLURAL:$1|гойту $1 агӀо}}}}",
"category-article-count-limited": "ХӀокху категори чохь {{PLURAL:$1|$1 агӀо|$1 агӀонаш}} цхьа агӀо бен яц.",
"category-file-count": "{{PLURAL:$2|ХӀокху категори чохь цхьа файл бе яц.|{{PLURAL:$1|Гойту $1 файл|Гойту $1 файлаш}} хӀокху категорешца кху $2.}}",
"category-file-count-limited": "ХӀокху категори чохь {{PLURAL:$1|$1 файл|$1 файлаш|1=цхьаъ бен файл яц}}.",
"preview": "Хьалха муха ю хьажа",
"showpreview": "Хьалха муха ю хьажар",
"showdiff": "Хlоттина болу хийцам",
+ "blankarticle": "<strong>ДӀахьедар:</strong> Ахьа кхуллуш йолу агӀо еса ю.\nЮху кнопка «{{int:savearticle}}» тӀетаӀаяхь, агӀо цхьа чулацам боцуш кхуллур ю.",
"anoneditwarning": "'''Тергам бе''': Ахьа хьай цӀарца тадарш деш дац. Хьан IP-адрес дӀаяздина хира ду хӀокху агӀон истори чу.",
"anonpreviewwarning": "''Системин чу цагӀахь хьан IP-адрес агӀона истори чу дӀаяз лур ду.''",
"missingcommenttext": "Дехар до дӀаязбе хайн хаам лахахь.",
"rev-deleted-event": "(дӀаяздар дӀаяьккхина)",
"rev-deleted-user-contribs": "[декъашхочун цӀе я IP-адрес дӀаяхина — къинхьегаман агӀонгара нисдар къайлаяьккхина]",
"rev-deleted-text-permission": "ХӀара агӀона верси '''дӀаяьккхина''' ю.\nБахьна далина [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дӀаяьхнарш йолу тептар чохь].",
+ "rev-suppressed-text-permission": "ХӀара агӀона верси <strong>къайлаяьккхина ю</strong>.\nБахьна далина [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} къайлаяьхарш йолу тептар чохь].",
"rev-deleted-text-unhide": "ХӀара агӀона верси '''дӀаяьккхина''' ю.\nБахьна далина [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дӀаяьхнарш йолу тептар чохь].\nХьайна лаахь хьа йиш ю [$1 и верси хьажа].",
"rev-suppressed-text-unhide": "ХӀара агӀона верси '''къайлаяьккхина''' ю.\nБахьна далина [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дӀаяьхнарш йолу тептар чохь].\nХьайна лаахь хьа йиш ю [$1 и верси хьажа].",
"rev-deleted-text-view": "ХӀара агӀона верси '''дӀаяьккхина''' ю.\nБахьна далина [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дӀаяьхнарш йолу тептар чохь].",
"emailsend": "ДӀадахьийта",
"emailccme": "Соьга а кхосса хааман копи.",
"emailccsubject": "$1: $2 бохьуьтучу хааман копи",
- "emailsent": "Ð\9aеÑ\85аÑ\82 дÓ\8fадахьийтина",
+ "emailsent": "Ð\9aеÑ\85аÑ\82 дÓ\80адахьийтина",
"emailsenttext": "Хьан электроннан хаам дӏабахьийтина.",
"emailuserfooter": "ХӀара хаам бахийтинера $1 {{GENDER:$1|декъащхочо}} $2 {{GENDER:$2|декъащхочунга}} «декъашхочунга хаам» олучу функцин гӀоьнца {{SITENAME}} проектан.",
"usermessage-summary": "Битта системан хаам.",
"import-upload": "Чуяха XML-хаамаш",
"import-token-mismatch": "Сеансан хаамаш дӀадайна. Дехар до, юху гӀорта.",
"import-invalid-interwiki": "Билгалйина вики чура импорт ян йиш яц.",
- "import-error-special": "«$1» агӀо импорт йина яц, и къастина цӀерийн меттигашан юкъайогӀуш хиларна.",
+ "import-error-edit": "«$1» агӀо хьуна таян цамагор бахьнехь и импорт цайина.",
+ "import-error-special": "«$1» агӀо импорт йина яц, и къастина цӀерийн меттигийн юкъайогӀуш хиларна.",
+ "import-error-invalid": "«$1» агӀо импорт цайина, оцунна импорт еш йолу цӀе хӀокху вики чохь ца магийна хилар бахьнехь.",
"importlogpage": "Импортан тептар",
"importlogpagetext": "Куьйгалхоша агӀонаш импорт яр царна бина хийцамашца кхечу википедеш чура.",
- "import-logentry-upload-detail": "$1 {{PLURAL:$1|верси|версеш}}",
+ "import-logentry-upload-detail": "$1 {{PLURAL:$1|верси импорт йина|версеш импорт йина}}",
"import-logentry-interwiki": "«$1» — викиюкъара импорт",
- "import-logentry-interwiki-detail": "$2 чура $1 {{PLURAL:$1|верси|версеш}}",
+ "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|верси импорт йина|версеш импорт йина}} $2 чура",
"javascripttest": "JavaScript хьажар",
"javascripttest-title": "$1 хьожуш бу",
"tooltip-pt-userpage": "Декъашхочуьна агlо",
"minutes-abbrev": "$1 мин",
"hours-abbrev": "$1 сахь.",
"seconds": "{{PLURAL:$1|$1 секунд|$1 секунд}}",
- "minutes": "{{PLURAL:$1|$1 минут|$1 минут}}",
+ "minutes": "{{PLURAL:$1|$1 минот|$1 минот}}",
"hours": "{{PLURAL:$1|$1 сахьт|$1 сахьт}}",
"days": "{{PLURAL:$1|$1 де|$1 де}}",
"weeks": "{{PLURAL:$1|$1 кӀира}}",
"ago": "$1 хьалха",
"just-now": "хӀинца",
"hours-ago": "$1 {{PLURAL:$1|сахьт}}",
- "minutes-ago": "$1 {{PLURAL:$1|минут}} хьалха",
+ "minutes-ago": "$1 {{PLURAL:$1|минот}} хьалха",
"seconds-ago": "$1 {{PLURAL:$1|секунд}} хьалха",
"monday-at": "оршотан дийнахь $1",
"tuesday-at": "шинара дийнахь $1",
"autosumm-replace": "АгӀона чуьраниг хийцина → «$1»",
"autoredircomment": "[[$1]] тӀе хьажийна",
"autosumm-new": "Керла агlо: «$1»",
+ "autosumm-newblank": "Кхоьллина еса агӀо",
"watchlistedit-normal-title": "Тергаме могӀанийн хийцамаш",
"watchlistedit-normal-legend": "Тергаме могӀам юкъар дӀаяккхар",
"watchlistedit-normal-explain": "Лахахь гойту хьан тергаме могӀамехь йолу агӀонаш.\nДӀаяздарш дӀадаха билгалде уьш такха тӀетаӀе кнопка «{{int:Watchlistedit-normal-submit}}».\nКхин хьа йиш ю [[Special:EditWatchlist/raw|йозан кепар могӀом нисба ]].",
"api-error-uploaddisabled": "ХӀокху вики чохь файлаш чуяхар дӀадайина ду.",
"api-error-verification-error": "ХӀара файл йоьхна я хила цаеза тайпан хила мега.",
"duration-seconds": "$1 {{PLURAL:$1|секунд}}",
- "duration-minutes": "$1 {{PLURAL:$1|минут}}",
+ "duration-minutes": "$1 {{PLURAL:$1|минот}}",
"duration-hours": "$1 {{PLURAL:$1|сахьт}}",
"duration-days": "$1 {{PLURAL:$1|де}}",
"duration-weeks": "$1 {{PLURAL:$1|кӀира}}",
"autosumm-replace": "Obsah stránky nahrazen textem „$1“",
"autoredircomment": "Přesměrování na [[$1]]",
"autosumm-new": "Založena nová stránka s textem „$1“",
+ "autosumm-newblank": "Založena prázdná stránka",
"size-kilobytes": "$1 KB",
"lag-warn-normal": "Změny za {{PLURAL:$1|poslední sekundu|poslední $1 sekundy|posledních $1 sekund}} nemusí být v tomto seznamu zobrazeny.",
"lag-warn-high": "Protože je databázový server právě mimořádně vytížen, nemusí být změny za {{PLURAL:$1|poslední sekundu|poslední $1 sekundy|posledních $1 sekund}} v tomto seznamu zobrazeny.",
"preview": "پیشنمایش",
"showpreview": "پیشنمایش",
"showdiff": "نمایش تغییرات",
+ "blankarticle": "<strong>هشدار:</strong> شما در حال ایجاد صفحه خالی هستید.\nاگر \"{{int:savearticle}}\" را دوباره کلیک کنید، صفحه بدون محتوا ایجاد میشود.",
"anoneditwarning": "'''هشدار:''' شما به سامانه وارد نشدهاید.\nنشانی آیپی شما در تاریخچهٔ ویرایش این صفحه ثبت خواهد شد.",
"anonpreviewwarning": "''شما به سامانه وارد نشدهاید. ذخیره کردن باعث میشود که نشانی آیپی شما در تاریخچهٔ این صفحه ثبت گردد.''",
"missingsummary": "'''یادآوری:''' شما خلاصهٔ ویرایش ننوشتهاید.\nاگر دوباره دکمهٔ «{{int:savearticle}}» را فشار دهید ویرایش شما بدون آن ذخیره خواهد شد.",
"rev-deleted-event": "(مورد از سیاهه پاک شده)",
"rev-deleted-user-contribs": "[نام کاربری یا نشانی آیپی حذف شده - ویرایش مخفی شده در مشارکتها]",
"rev-deleted-text-permission": "این ویرایش از این صفحه '''حذف شدهاست'''.\nممکن است اطلاعات مرتبط با آن در [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] موجود باشد.",
+ "rev-suppressed-text-permission": "این ویرایش از این صفحه '''حذف شدهاست'''.\nشما میتوانید آن را ببینید؛ ممکن است اطلاعات مرتبط با آن در [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] موجود باشد.",
"rev-deleted-text-unhide": "این ویرایش از این صفحه '''حذف شدهاست'''.\nممکن است اطلاعات مرتبط با آن در [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] موجود باشد.\nشما کماکان میتوانید در صورت تمایل [$1 این نسخه را ببینید].",
"rev-suppressed-text-unhide": "این ویرایش از این صفحه '''فرونشانده شدهاست'''.\nممکن است اطلاعات مرتبط با آن در [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} سیاههٔ فرونشانی] موجود باشد.\nشما کماکان میتوانید در صورت تمایل [$1 این نسخه را ببینید].",
"rev-deleted-text-view": "این ویرایش از این صفحه '''حذف شدهاست'''.\nشما میتوانید آن را ببینید؛ ممکن است اطلاعات مرتبط با آن در [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] موجود باشد.",
"recentchanges-legend-heading": "'''اختصارها:'''",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (همچنین به [[Special:NewPages|فهرست صفحات جدید]] نگاه کنید)",
"recentchanges-legend-plusminus": "('' ±۱۲۳'')",
- "rcnotefrom": "در زیر تغییرات از <strong>$2</strong> (تا <strong>$1</strong> نشان داده شدهاست).",
+ "rcnotefrom": "در زیر تغییرات از <strong>$3, $4</strong> (تا <strong>$1</strong> {{PLURAL:$5|نشان داده شدهاست|نشان داده شدهاند}}).",
"rclistfrom": "نمایش تغییرات جدید با شروع از $3 $2",
"rcshowhideminor": "$1 ویرایشهای جزئی",
"rcshowhideminor-show": "نمایش",
"import-upload": "بارگذاری داده اکسامال",
"import-token-mismatch": "از دست رفتن اطلاعات نشست کاربری. لطفاً دوباره امتحان کنید.",
"import-invalid-interwiki": "از ویکی مشخص شده نمیتوان درونریزی انجام داد.",
- "import-error-edit": "صفحهٔ «$1» وارد نمیشود، چون شما مجاز به ویرایش آن نیستید.",
- "import-error-create": "صفحهٔ «$1» وارد نمیشود، چون شما مجاز به ایجاد آن نیستید.",
+ "import-error-edit": "صفحهٔ «$1» وارد نشد، چون شما مجاز به ویرایش آن نیستید.",
+ "import-error-create": "صفحهٔ «$1» وارد نشد، چون شما مجاز به ایجاد آن نیستید.",
"import-error-interwiki": "صفحه «$1» وارد نشد. چون نام آن برای پیوند خارجی (interwiki) رزرو شدهاست.",
"import-error-special": "صفحهٔ «$1» درونریزی نشد، چرا که متعلق به فضای نام نامجاز است.",
- "import-error-invalid": "صفحه \"$1\" به دلیل نامعتبر بودن نامش وارد نمیشود.",
+ "import-error-invalid": "صفحه \"$1\" به دلیل نامعتبر بودن نامش که ممکن بود در ویکی نامعتبر باشد، وارد نشد.",
"import-error-unserialize": "امکان خارج کردن نسخهٔ $2 از صفحهٔ «$1» از حالت سریالشده وجود نداشت. گزارش شد که نسخه از مدل محتوای $3 استفاده میکند که به صورت $4 سریال شدهاست.",
"import-error-bad-location": "بازبینی $2 با استفاده از مدل محتوای $3 نمیتواند در \"$1\" در این ویکی ذخیره شده باشد، از آنجایی که مدل در آن صفحه پشتیبانی نشدهاست.",
"import-options-wrong": "{{PLURAL:$2|جزئیات|جزئیات}} اشتباه: <nowiki>$1</nowiki>",
"importlogpage": "سیاههٔ درونریزیها",
"importlogpagetext": "درونریزی صفحهها به همراه تاریخچهٔ ویرایش آنها از ویکیهای دیگر.",
"import-logentry-upload": "[[$1]] را از طریق بارگذاری پرونده درونریزی کرد",
- "import-logentry-upload-detail": "$1 {{PLURAL:$1|نسخه|نسخه}}",
+ "import-logentry-upload-detail": "$1 {{PLURAL:$1|نسخه|نسخه}} واردشده",
"import-logentry-interwiki": "$1 را تراویکی کرد",
- "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|نسخه|نسخه}} از $2",
+ "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|نسخه|نسخه}} واردشده از $2",
"javascripttest": "آزمایش جاوا اسکریپت",
"javascripttest-title": "در حال اجرای آزمایشهای $1",
"javascripttest-pagetext-noframework": "این صفحه برای اجرای آزمایشهای جاوا اسکریپت کنار گذاشته شدهاست.",
"autosumm-replace": "جایگزینی صفحه با '$1'",
"autoredircomment": "تغییرمسیر به [[$1]]",
"autosumm-new": "صفحهای جدید حاوی «$1» ایجاد کرد",
+ "autosumm-newblank": "ایجاد صفحه خالی",
"size-bytes": "$1 بایت",
"size-kilobytes": "$1 کیلوبایت",
"size-megabytes": "$1 مگابایت",
"preview": "Esikatselu",
"showpreview": "Esikatsele",
"showdiff": "Näytä muutokset",
+ "blankarticle": "<strong>Varoitus:</strong> Sivu, jota olet luomassa, on tyhjä.\nJos napsautat \"{{int:savearticle}}\" uudelleen, sivu luodaan ilman sisältöä.",
"anoneditwarning": "'''Varoitus:''' Et ole kirjautunut sisään.\nIP-osoitteesi kirjataan tämän sivun muutoshistoriaan.",
"anonpreviewwarning": "''Et ole kirjautunut sisään. Tallentaminen kirjaa IP-osoitteesi tämän sivun muutoshistoriaan.''",
"missingsummary": "Et ole antanut yhteenvetoa. Jos valitset Tallenna uudelleen, niin muokkauksesi tallennetaan ilman yhteenvetoa.",
"rev-deleted-event": "(lokitapahtuma poistettu)",
"rev-deleted-user-contribs": "[käyttäjätunnus tai IP-osoite poistettu – muokkaus on piilotettu muokkausluettelosta]",
"rev-deleted-text-permission": "Tämä versio sivusta on '''poistettu'''.\nLisätietoja löytyy [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} poistolokista].",
+ "rev-suppressed-text-permission": "Tämä versio sivusta on <strong>häivytetty</strong>.\nLisätietoja löytyy [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} häivytyslokista].",
"rev-deleted-text-unhide": "Tämä versio sivusta on '''poistettu'''.\nLisätietoja löytyy [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} poistolokista].\nVoit silti [$1 nähdä tämän muutoksen], jos haluat jatkaa.",
"rev-suppressed-text-unhide": "Tämä versio sivusta on '''häivytetty'''.\nLisätietoja löytyy [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} häivytyslokista].\nVoit silti [$1 nähdä tämän muutoksen], jos haluat jatkaa.",
"rev-deleted-text-view": "Tämä versio sivusta on '''poistettu'''.\nVoit silti nähdä sen. Lisätietoja löytyy [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} poistolokista].",
"autosumm-replace": "Ak: Sivun sisältö korvattiin sisällöllä ”$1”",
"autoredircomment": "Ak: Ohjaus sivulle [[$1]]",
"autosumm-new": "Ak: Uusi sivu: $1",
+ "autosumm-newblank": "Tyhjä sivu luotu",
"size-kilobytes": "$1 KiB",
"size-megabytes": "$1 MiB",
"size-gigabytes": "$1 GiB",
"rev-deleted-event": "(entrée retirée)",
"rev-deleted-user-contribs": "[nom d'utilisateur ou adresse IP retiré - modification masquée sur les contributions]",
"rev-deleted-text-permission": "Cette version de la page a été '''effacée'''.\nDes détails sont disponibles dans le [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} journal des effacements].",
- "rev-suppressed-text-permission": "Cette révision de la page a été <strong>supprimée</strong>.\nLes détails se trouvent dans le [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} journal des suppressions].",
+ "rev-suppressed-text-permission": "Cette version de la page a été <strong>supprimée</strong>.\nLes détails se trouvent dans le [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} journal des suppressions].",
"rev-deleted-text-unhide": "Cette version de la page a été '''effacée'''.\nDes détails sont disponibles dans [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} le journal des effacements].\nVous pouvez toujours [$1 voir cette version] si vous le voulez.",
"rev-suppressed-text-unhide": "Cette version de la page a été '''supprimée'''.\nDes détails sont disponibles dans [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} le journal des suppression].\nVous pouvez toujours [$1 voir cette version] si vous le voulez.",
"rev-deleted-text-view": "Cette version de la page a été '''effacée'''.\nVous pouvez la visualiser ; des détails sont disponibles dans le [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} journal des effacements].",
"import-upload": "Import de données XML",
"import-token-mismatch": "Perte des données de session. Veuillez réessayez.",
"import-invalid-interwiki": "Impossible d'importer depuis le wiki spécifié.",
- "import-error-edit": "La page « $1 » n’a pas été importée parce que vous n’êtes pas autorisés à la modifier.",
- "import-error-create": "La page « $1 » n’a pas été importée parce que vous n’êtes pas autorisés à la créer.",
+ "import-error-edit": "La page « $1 » n’a pas été importée parce que vous n’êtes pas autorisé à la modifier.",
+ "import-error-create": "La page « $1 » n’a pas été importée parce que vous n’êtes pas autorisé à la créer.",
"import-error-interwiki": "La page « $1 » n’a pas été importée parce que son nom est réservé pour un lien externe (interwiki).",
- "import-error-special": "La page « $1 » n’a pas été importée parce qu’elle appartient à un espace de noms spécial qui n’en autorise aucune.",
+ "import-error-special": "La page « $1 » n’a pas été importée parce qu’elle appartient à un espace de noms spécial qui n’autorise aucune page.",
"import-error-invalid": "Page « $1 » n’a pas été importée parce que le nom sous lequel elle aurait été importée n’est pas valide sur ce wiki.",
"import-error-unserialize": "La révision $2 de la page « $1 » ne peut pas être désérialisée. La révision est indiquée comme utilisant le modèle de contenu $3 sérialisé en $4.",
"import-error-bad-location": "La révision $2 utilisant le modèle de contenu $3 n’a pas pu être stocké sur « $1 » sur ce wiki, car ce modèle n’est pas supporté sur cette page.",
"autosumm-replace": "Pagina sostituita con '$1'",
"autoredircomment": "Redirect alla pagina [[$1]]",
"autosumm-new": "Creata pagina con \"$1\"",
+ "autosumm-newblank": "Creata pagina vuota",
"size-bytes": "$1 byte",
"lag-warn-normal": "Le modifiche apportate {{PLURAL:$1|nell'ultimo secondo|negli ultimi $1 secondi}} potrebbero non apparire in questa lista.",
"lag-warn-high": "A causa di un eccessivo ritardo nell'aggiornamento del server di database, le modifiche apportate {{PLURAL:$1|nell'ultimo secondo|negli ultimi $1 secondi}} potrebbero non apparire in questa lista.",
"talkpagelinktext": "thó-lūn",
"specialpage": "Te̍k-sû-ia̍h",
"personaltools": "Kò-jîn kang-khū",
- "postcomment": "加一段",
"articlepage": "Khoàⁿ loē-iông ia̍h",
"talk": "thó-lūn",
"views": "Khoàⁿ",
"editinginterface": "'''Sè-jī:''' Lí tng teh siu-kái 1 bīn thê-kiong nńg-thé kài-bīn bûn-jī ê ia̍h. Jīn-hô kái-piàn to ē éng-hióng tio̍h kî-thaⁿ iōng-chiá ê sú-iōng kài-bīn. Nā beh kái hoan-e̍k, chhiaⁿ khì Ûi-ki Mûi-thé chāi-tē-hoà sū-kang [//translatewiki.net/ translatewiki.net] hiâ.",
"cascadeprotected": "Chit-ê ia̍h í-keng hông pó-hō͘ bē kái tit. In-ūi i tī ē-bīn {{PLURAL:$1|ê|ê}} liân-só pó-hō͘ lāi-té:\n$2",
"namespaceprotected": "Lí bô khoân-lī kái '''$1''' miâ-khong-kan ê ia̍h",
+ "customcssprotected": "你無受權去改這个 CSS頁,因為這个頁有包括別个用者的個人設定。",
+ "customjsprotected": "你無授權去改這个JavaScript頁,因為這个頁包括別个用者的個人設定。",
+ "mycustomcssprotected": "你無授權去改這个CSS頁。",
+ "mycustomjsprotected": "你無授權去改這个JavaScript頁。",
+ "myprivateinfoprotected": "你無授權改你家己的私人資訊。",
+ "mypreferencesprotected": "你無授權改你的家己的喜愛設定。",
+ "ns-specialprotected": "特殊頁袂得改。",
+ "titleprotected": "這个標題已經予[[User:$1|$1]]保護起來,袂得提來用。\n原因是 \"<em>$2</em>。",
+ "filereadonlyerror": "因為檔案庫這馬只會使看,所以袂得改 \"$1\"這个檔案。\n鎖檔案庫的管理員講是因為:\"$3\"。",
"exception-nologin": "Bô teng-ji̍p",
"exception-nologin-text": "請先[[Special:Userlogin|登入]]了才有法度看這頁抑對這頁做動作。",
"exception-nologin-text-manual": "請先$1,才有法度看這頁抑對這頁做動作。",
"externaldberror": "這可能是資料庫驗證錯誤,抑是無允准你改外部的口座。",
"login": "Teng-ji̍p",
"nav-login-createaccount": "Teng-ji̍p / khui sin kháu-chō",
- "loginprompt": "Thiⁿ ē-kha ê chu-liāu thang khui sin hō·-thâu a̍h-sī teng-ji̍p {{SITENAME}}.",
"userlogin": "Teng-ji̍p / khui sin kháu-chō",
"userloginnocreate": "Teng-ji̍p",
"logout": "Teng-chhut",
"unusedimagestext": "<p>Chhiáⁿ chù-ì: kî-thaⁿ ê bāng-chām ū khó-lêng iōng URL ti̍t-chiap liân kàu iáⁿ-siōng, só·-í sui-jiân chhiâng-chāi teh iōng, mā sī ē lia̍t tī chia.</p>",
"unusedcategoriestext": "Ū ē-kha chiah-ê lūi-pia̍t-ia̍h, m̄-koh bô kî-thaⁿ ê bûn-chiuⁿ a̍h-sī lūi-pia̍t lī-iōng.",
"booksources": "Tô͘-su chu-liāu",
- "specialloguserlabel": "Iōng-chiá:",
- "speciallogtitlelabel": "Sû-tiâu:",
+ "specialloguserlabel": "做的人:",
+ "speciallogtitlelabel": "目地(標題抑是用者)",
"log": "記錄",
"logempty": "Log lāi-bīn bô sio-tùi ê hāng-bo̍k.",
"allpages": "Só·-ū ê ia̍h",
"preview": "Forhåndsvisning",
"showpreview": "Forhåndsvisning",
"showdiff": "Vis endringer",
+ "blankarticle": "<strong>Advarsel:</strong> Siden du er i ferd med å opprette er tom.\nHvis du trykker \"{{int:savearticle}}\" en gang til, vil siden opprettes uten innhold.",
"anoneditwarning": "'''Advarsel:''' Du er ikke logget inn.\nIP-adressen din blir bevart i sidens redigeringshistorikk.",
"anonpreviewwarning": "''Du er ikke logget inn. Lagring vil registrere din IP-adresse i sidens redigeringshistorikk.''",
"missingsummary": "'''Påminnelse:''' Du har ikke lagt inn en redigeringsforklaring.\nVelger du ''Lagre siden'' en gang til blir endringene lagret uten forklaring.",
"rev-deleted-event": "(fjernet loggoppføring)",
"rev-deleted-user-contribs": "[brukernavn eller IP-adresse fjernet – redigeringen vises ikke blant bidragene]",
"rev-deleted-text-permission": "Denne revisjonen har blitt '''slettet'''.\nDet kan være detaljer i [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} slettingsloggen].",
+ "rev-suppressed-text-permission": "Denne siderevisjonen har blitt <strong>skjult</strong>.\nDetaljer finnes i [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} skjulingsloggen].",
"rev-deleted-text-unhide": "Denne siderevisjonen har blitt '''slettet'''.\nSe etter detaljer i slettingsloggen: [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}}].\nDu kan fortsatt [$1 se revisjonen] om du ønsker det.",
"rev-suppressed-text-unhide": "Denne siderevisjonen har blitt '''skjult'''.\nInformasjon om dette kan finnes i [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} skjulingsloggen].\nDu kan fortsatt [$1 se revisjonen] om du ønsker det.",
"rev-deleted-text-view": "Denne siderevisjonen har blitt '''slettet'''.\nDu kan fortsatt se den; detaljer finnes i [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} slettingsloggen].",
"revdelete-text-text": "Slettede revisjoner vil fortsatt finnes i sidens historikk, men deler av deres innhold vil være utilgjengelige for offentligheten.",
"revdelete-text-file": "Slettede filversjoner vil fortsatt finnes i filhistorikken, men deler av deres innhold vil være utilgjengelige for offentligheten.",
"logdelete-text": "Slettede hendelser i loggen vil fortsatt finnes i loggene, men deler av deres innhold vil være utilgjengelige for offentligheten.",
- "revdelete-text-others": "Andre administratorer på {{SITENAME}} vil fortsatt ha tilgang til det skjulte innholdet og kan rulle det tilbake igjen via det samme grensesnittet, hvis ikke ytterligere begrensinger er satt.",
+ "revdelete-text-others": "Andre administratorer vil fortsatt ha tilgang til det skjulte innholdet og kan hente det frem igjen, hvis ikke ytterligere begrensinger er satt.",
"revdelete-confirm": "Bekreft at du ønsker å gjøre dette, at du forstår konsekvensene, og at du gjør det i samsvar med [[{{MediaWiki:Policy-url}}|retningslinjene]].",
"revdelete-suppress-text": "Skjuling bør '''kun''' brukes i følgende tilfeller:\n* Mulig injurierende utsagn\n* Følsomme personlige opplysninger\n*: ''privatadresser og -telefonnumre, fødselsnumre og lignende''",
"revdelete-legend": "Fastsett synlighetsbegrensninger",
"right-deletedtext": "Vise slettet tekst og endringer mellom slettede versjoner",
"right-browsearchive": "Søke i slettede sider",
"right-undelete": "Gjenopprette sider",
- "right-suppressrevision": "Se og gjenopprette skjulte siderevisjoner",
+ "right-suppressrevision": "Se på, skjul og hent frem igjen spesifikke siderevisjoner for alle brukere",
+ "right-viewsuppressed": "Se på revisjoner som er skjult for alle brukere",
"right-suppressionlog": "Se private logger",
"right-block": "Blokkere andre brukere fra å redigere",
"right-blockemail": "Blokkere brukere fra å sende e-post",
"recentchanges-legend-heading": "'''Tegnforklaring:'''",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (se også [[Special:NewPages|liste av nye sider]])",
"recentchanges-legend-plusminus": "«(±123)»",
- "rcnotefrom": "Nedenfor er endringene gjort siden <strong>$2</strong> (frem til <strong>$1</strong> vises).",
+ "rcnotefrom": "Nedenfor er vist {{PLURAL:$5|endringen|endringene}} som er gjort siden <strong>$3, $4</strong> (frem til <strong>$1</strong>).",
"rclistfrom": "Vis nye endringer fra og med $3 $2",
"rcshowhideminor": "$1 mindre endringer",
"rcshowhideminor-show": "Vis",
"license": "Lisens:",
"license-header": "Lisensiering",
"nolicense": "Ingen spesifisert",
+ "licenses-edit": "Rediger lisensvalg",
"license-nopreview": "(Forhåndsvisning ikke tilgjengelig)",
"upload_source_url": " (en gyldig, offentlig tilgjengelig adresse)",
"upload_source_file": " (en fil på din datamaskin)",
"wantedpages-badtitle": "Ugyldig tittel i resultatene: $1",
"wantedfiles": "Ønskede filer",
"wantedfiletext-cat": "Følgende filer refereres, men eksisterer ikke. Filer fra fremmede samlinger kan listes selv om de ikke finnes. Alle slik falske treff vil <del>strykes</del>. I tillegg er sider som har innebygde, ikke-eksisterende filer listet opp i [[:$1]].",
+ "wantedfiletext-cat-noforeign": "Følgende filer er i bruk, men finnes ikke. I tillegg er sider som inkluderer ikke-eksisterende filer gitt i [[:$1]].",
"wantedfiletext-nocat": "Følgende filer er referert, men eksisterer ikke. Filer fra fremmede samlinger kan være opplistet selv om de ikke finnes. Alle slike falske referanser vil bli <del>fjernet</del>.",
+ "wantedfiletext-nocat-noforeign": "Følgende filer er i bruk, men finnes ikke.",
"wantedtemplates": "Etterspurte maler",
"mostlinked": "Sider med flest lenker til seg",
"mostlinkedcategories": "Kategorier med flest sider",
"import-upload": "Last opp XML-data",
"import-token-mismatch": "Sesjonsdata mistet. Venligst prøv igjen.",
"import-invalid-interwiki": "Kan ikke importere fra angitt wiki.",
- "import-error-edit": "Siden «$1» ble ikke importert siden du ikke har tillatelse til å redigere den.",
- "import-error-create": "Siden «$1» ble ikke importert siden du ikke har tillatelse til å opprette den.",
- "import-error-interwiki": "Siden «$1» ble ikke importert fordi navnet er reservert for ekstern lenking (interwiki).",
- "import-error-special": "Siden «$1» ble ikke importert fordi den tilhører et spesialnavnerom som ikke tillater sider.",
- "import-error-invalid": "Siden «$1» ble ikke importert fordi navnet er ugyldig.",
+ "import-error-edit": "Siden «$1» ble ikke importert fordi du ikke har tillatelse til å redigere den.",
+ "import-error-create": "Siden «$1» ble ikke importert fordi du ikke har tillatelse til å opprette den.",
+ "import-error-interwiki": "Siden «$1» ble ikke importert fordi dette navnet er reservert for ekstern lenking (interwiki).",
+ "import-error-special": "Siden «$1» ble ikke importert fordi dette navnet tilhører et spesialnavnerom som ikke tillater sider.",
+ "import-error-invalid": "Siden «$1» ble ikke importert fordi sidenavnet er ugyldig på denne wikien.",
"import-error-unserialize": "Revisjon $2 av siden «$1» kunne ikke serialiseres. Det ble rapportert at revisjonen bruker innholdsmodellen $3 serialisert som $4.",
"import-error-bad-location": "Revisjon $2 som bruker innholdsmodell $3 kan ikke lagres til \"$1\" på denne wikien siden denne modellen ikke støttes på den siden.",
"import-options-wrong": "Feil {{PLURAL:$2|opsjon|opsjoner}}: <nowiki>$1</nowiki>",
"importlogpage": "Importlogg",
"importlogpagetext": "Administrativ import av sider med redigeringshistorikk fra andre wikier.",
"import-logentry-upload": "importerte [[$1]] ved opplasting",
- "import-logentry-upload-detail": "Importerte {{PLURAL:$1|én revisjon|$1 revisjoner}}",
+ "import-logentry-upload-detail": "{{PLURAL:$1|\\Én revisjon|$1 revisjoner}} er importert",
"import-logentry-interwiki": "transwikiimporterte $1",
- "import-logentry-interwiki-detail": "{{PLURAL:$1|Én revisjon|$1 revisjoner}} fra $2",
+ "import-logentry-interwiki-detail": "{{PLURAL:$1|Én revisjon|$1 revisjoner}} er importert fra $2",
"javascripttest": "JavaScript-testing",
"javascripttest-title": "Kjører $1 tester",
"javascripttest-pagetext-noframework": "Denne siden er reservert for å kjøre JavaScript-tester.",
"autosumm-replace": "Erstatter siden med «$1»",
"autoredircomment": "Omdirigerer til [[$1]]",
"autosumm-new": "Ny side: $1",
+ "autosumm-newblank": "Opprettet tom side",
"lag-warn-normal": "Endringer nyere enn $1 {{PLURAL:$1|sekund|sekunder}} vises muligens ikke i denne listen.",
"lag-warn-high": "På grunn av stor databaseforsinkelse, vil ikke endringer som er nyere enn $1 {{PLURAL:$1|sekund|sekunder}} vises i denne listen.",
"watchlistedit-normal-title": "Rediger overvåkningsliste",
"signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|diskusjon]])",
"unknown_extension_tag": "Ukjent tilleggsmerking «$1»",
"duplicate-defaultsort": "Advarsel: Standardsorteringen «$2» tar over for den tidligere sorteringen «$1».",
+ "duplicate-displaytitle": "<strong>Advarsel:</strong> Visningstittel \"$2\" erstatter tidligere visningstittel \"$1\".",
"version": "Versjon",
"version-extensions": "Installerte utvidelser",
"version-skins": "Installerte drakter",
"gotaccountlink": "Anmelden",
"userlogin-resetlink": "Bi'j de anmeldgegevens kwiet?",
"userlogin-resetpassword-link": "Joew wachtwoord vergeten?",
+ "userlogin-helplink2": "Hulpe bie t anmelden",
"userlogin-loggedin": "Je bin al an-emeld as {{GENDER:$1|$1}}.\nGebruuk t onderstaonde formulier um an te melden as n aandere gebruker.",
"userlogin-createanother": "n Aandere gebrukerskonto anmaken",
"createacct-emailrequired": "Netpostadres",
"아라",
"Mar(c)",
"Calak",
- "Arg"
+ "Arg",
+ "NCoppens"
]
},
"tog-underline": "Koppelingen onderstrepen:",
"tog-watchdefault": "Pagina’s en bestanden die ik bewerk automatisch volgen",
"tog-watchmoves": "Pagina’s en bestanden die ik hernoem automatisch volgen",
"tog-watchdeletion": "Pagina’s en bestanden die ik verwijder automatisch volgen",
- "tog-minordefault": "Mijn bewerkingen als ‘klein’ markeren",
+ "tog-minordefault": "Mijn bewerkingen standaard als ‘klein’ markeren",
"tog-previewontop": "Voorvertoning boven bewerkingsveld weergeven",
"tog-previewonfirst": "Voorvertoning bij eerste bewerking weergeven",
"tog-enotifwatchlistpages": "Mij e-mailen bij bewerkingen van pagina’s of bestanden op mijn volglijst",
"mergehistory-empty": "Er zijn geen versies die samengevoegd kunnen worden.",
"mergehistory-success": "$3 {{PLURAL:$3|versie|versies}} van [[:$1]] zijn succesvol samengevoegd naar [[:$2]].",
"mergehistory-fail": "Kan geen geschiedenis samenvoegen, controleer opnieuw de pagina- en tijdinstellingen.",
+ "mergehistory-fail-toobig": "Niet in staat om geschiedenis samen te voegen omdat meer dan de limiet van $1 {{PLURAL:$1|revisie zou|revisies zouden}} worden verplaatst.",
"mergehistory-no-source": "De bronpagina $1 bestaat niet.",
"mergehistory-no-destination": "De bestemmingspagina $1 bestaat niet.",
"mergehistory-invalid-source": "De bronpagina moet een geldige paginanaam zijn.",
"signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|overleg]])",
"unknown_extension_tag": "Onbekende tag \"$1\"",
"duplicate-defaultsort": "'''Waarschuwing:''' de standaardsortering \"$2\" krijgt voorrang voor de sortering \"$1\".",
+ "duplicate-displaytitle": "<strong>Waarschuwing:</strong>Titelweergave \"$2\" overschrijft eerdere titelweergave \"$1\".",
"version": "Versie",
"version-extensions": "Geïnstalleerde uitbreidingen",
"version-skins": "Geïnstalleerde vormgevingen",
"expand_templates_generate_xml": "XML-parserboom bekijken",
"expand_templates_generate_rawhtml": "Ruwe HTML weergeven",
"expand_templates_preview": "Voorvertoning",
+ "pagelanguage": "Taal pagina kiezen",
"pagelang-name": "Pagina",
"pagelang-language": "Taal",
- "pagelang-select-lang": "Taal selecteren"
+ "pagelang-use-default": "Gebruik standaard taal",
+ "pagelang-select-lang": "Taal selecteren",
+ "right-pagelang": "Taal van de pagina wijzigen",
+ "action-pagelang": "Taal van de pagina wijzigen",
+ "log-name-pagelang": "Logboek van taalwijzigingen",
+ "log-description-pagelang": "Dit is een logboek van wijzigingen van de taal van pagina's.",
+ "logentry-pagelang-pagelang": "$1 wijzigde de taal van de pagina '$3' van $4 naar $5."
}
"content-model-javascript": "JavaScript",
"content-model-css": "CSS",
"expensive-parserfunction-warning": "<strong>警告:</strong>这个页面有太多高昂的语法功能调用。\n\n它应该少过$2次呼叫,现在有$1次呼叫。",
- "expensive-parserfunction-category": "有过多高开销解析器函数调用的页面",
+ "expensive-parserfunction-category": "页面中有太多耗费的语法功能呼叫",
"post-expand-template-inclusion-warning": "'''警告:'''包含模板大小过大。\n一些模板将不会包含。",
- "post-expand-template-inclusion-category": "模板包含大小超限的页面",
+ "post-expand-template-inclusion-category": "模板包含上限已经超过的页面",
"post-expand-template-argument-warning": "'''警告:'''本页面包含至少一个模板参数有过大扩展大小。这些参数会被略过。",
"post-expand-template-argument-category": "含有略过模板参数的页面",
"parser-template-loop-warning": "检查到模板循环:[[$1]]",
"parser-template-recursion-depth-warning": "模板递归深度越限($1)",
"language-converter-depth-warning": "字词转换器深度越限($1)",
- "node-count-exceeded-category": "节点数超限的页面",
+ "node-count-exceeded-category": "页面的节点数超出限制",
"node-count-exceeded-category-desc": "节点数溢出页面的分类。",
"node-count-exceeded-warning": "页面超出了节点数",
- "expansion-depth-exceeded-category": "展开深度超限的页面",
+ "expansion-depth-exceeded-category": "扩展深度超出限制的页面",
"expansion-depth-exceeded-category-desc": "这是超出拓展深度页面的分类。",
"expansion-depth-exceeded-warning": "页面超过了扩展深度",
"parser-unstrip-loop-warning": "检测到回圈",
"userrights-changeable-col": "您可變更的群組",
"userrights-unchangeable-col": "您不可變更的群組",
"userrights-conflict": "使用者權限更改發生衝突!請重新檢視並確認你的更改。",
- "userrights-removed-self": "您已成功移除自己的權限,故此您沒法再次訪問此頁。",
+ "userrights-removed-self": "您已成功移除自己的權限,故此您無法再次存取此頁。",
"group": "群組:",
"group-user": "使用者",
"group-autoconfirmed": "自動確認使用者",
"exif-contrast": "對比度",
"exif-saturation": "飽和度",
"exif-sharpness": "銳利度",
- "exif-devicesettingdescription": "è¨å\82\99設定描述",
+ "exif-devicesettingdescription": "è£\9dç½®設定描述",
"exif-subjectdistancerange": "主體距離範圍",
"exif-imageuniqueid": "唯一影像識別碼",
"exif-gpsversionid": "GPS 標籤版本",
"limitreport-cputime-value": "$1 秒",
"limitreport-walltime": "實際使用時間",
"limitreport-walltime-value": "$1 秒",
- "limitreport-ppvisitednodes": "預處理器訪問節點次數",
+ "limitreport-ppvisitednodes": "預處理機訪問節點次數",
"limitreport-ppgeneratednodes": "預處理器產生節點次數",
"limitreport-postexpandincludesize": "展開後的引用大小",
"limitreport-postexpandincludesize-value": "$1/$2 個{{PLURAL:$2|位元組}}",
--- /dev/null
+<?php
+/**
+ * Maintenance script to wrap all old-style passwords in a layered type
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Maintenance script to wrap all passwords of a certain type in a specified layered
+ * type that wraps around the old type.
+ *
+ * @since 1.24
+ * @ingroup Maintenance
+ */
+class WrapOldPasswords extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Wrap all passwords of a certain type in a new layered type";
+ $this->addOption( 'type',
+ 'Password type to wrap passwords in (must inherit LayeredParameterizedPassword)', true, true );
+ $this->addOption( 'verbose', 'Enables verbose output', false, false, 'v' );
+ $this->setBatchSize( 100 );
+ }
+
+ public function execute() {
+ global $wgAuth;
+
+ if ( !$wgAuth->allowSetLocalPassword() ) {
+ $this->error( '$wgAuth does not allow local passwords. Aborting.', true );
+ }
+
+ $passwordFactory = new PasswordFactory();
+ $passwordFactory->init( RequestContext::getMain()->getConfig() );
+
+ $typeInfo = $passwordFactory->getTypes();
+ $layeredType = $this->getOption( 'type' );
+
+ // Check that type exists and is a layered type
+ if ( !isset( $typeInfo[$layeredType] ) ) {
+ $this->error( 'Undefined password type', true );
+ }
+
+ $passObj = $passwordFactory->newFromType( $layeredType );
+ if ( !$passObj instanceof LayeredParameterizedPassword ) {
+ $this->error( 'Layered parameterized password type must be used.', true );
+ }
+
+ // Extract the first layer type
+ $typeConfig = $typeInfo[$layeredType];
+ $firstType = $typeConfig['types'][0];
+
+ // Get a list of password types that are applicable
+ $dbw = $this->getDB( DB_MASTER );
+ $typeCond = 'user_password' . $dbw->buildLike( ":$firstType:", $dbw->anyString() );
+
+ $minUserId = 0;
+ do {
+ $dbw->begin();
+
+ $res = $dbw->select( 'user',
+ array( 'user_id', 'user_name', 'user_password' ),
+ array(
+ 'user_id > ' . $dbw->addQuotes( $minUserId ),
+ $typeCond
+ ),
+ __METHOD__,
+ array(
+ 'ORDER BY' => 'user_id',
+ 'LIMIT' => $this->mBatchSize,
+ 'LOCK IN SHARE MODE',
+ )
+ );
+
+ /** @var User[] $updateUsers */
+ $updateUsers = array();
+ foreach ( $res as $row ) {
+ if ( $this->hasOption( 'verbose' ) ) {
+ $this->output( "Updating password for user {$row->user_name} ({$row->user_id}).\n" );
+ }
+
+ $user = User::newFromId( $row->user_id );
+ /** @var ParameterizedPassword $password */
+ $password = $passwordFactory->newFromCiphertext( $row->user_password );
+ /** @var LayeredParameterizedPassword $layeredPassword */
+ $layeredPassword = $passwordFactory->newFromType( $layeredType );
+ $layeredPassword->partialCrypt( $password );
+
+ $updateUsers[] = $user;
+ $dbw->update( 'user',
+ array( 'user_password' => $layeredPassword->toString() ),
+ array( 'user_id' => $row->user_id ),
+ __METHOD__
+ );
+
+ $minUserId = $row->user_id;
+ }
+
+ $dbw->commit();
+
+ // Clear memcached so old passwords are wiped out
+ foreach ( $updateUsers as $user ) {
+ $user->clearSharedCache();
+ }
+ } while ( $res->numRows() );
+ }
+}
+
+$maintClass = "WrapOldPasswords";
+require_once RUN_MAINTENANCE_IF_MAIN;
// skin over-rides common content styling.
'skinStyles' => array(
'default' => 'resources/src/mediawiki.skinning/content.parsoid.less',
- 'minerva' => array(),
),
'targets' => array( 'desktop', 'mobile' ),
),
'resources/lib/jquery.ui/themes/smoothness/jquery.ui.core.css',
'resources/lib/jquery.ui/themes/smoothness/jquery.ui.theme.css',
),
- 'vector' => array(
- 'resources/src/jquery.ui-themes/vector/jquery.ui.core.css',
- 'resources/src/jquery.ui-themes/vector/jquery.ui.theme.css',
- ),
),
'group' => 'jquery.ui',
),
),
'skinStyles' => array(
'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.accordion.css',
- 'vector' => 'resources/src/jquery.ui-themes/vector/jquery.ui.accordion.css',
),
'group' => 'jquery.ui',
),
),
'skinStyles' => array(
'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.autocomplete.css',
- 'vector' => 'resources/src/jquery.ui-themes/vector/jquery.ui.autocomplete.css',
),
'group' => 'jquery.ui',
),
),
'skinStyles' => array(
'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.button.css',
- 'vector' => 'resources/src/jquery.ui-themes/vector/jquery.ui.button.css',
),
'group' => 'jquery.ui',
),
'dependencies' => 'jquery.ui.core',
'skinStyles' => array(
'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.datepicker.css',
- 'vector' => 'resources/src/jquery.ui-themes/vector/jquery.ui.datepicker.css',
),
'languageScripts' => array(
'af' => 'resources/lib/jquery.ui/i18n/jquery.ui.datepicker-af.js',
),
'skinStyles' => array(
'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.dialog.css',
- 'vector' => 'resources/src/jquery.ui-themes/vector/jquery.ui.dialog.css',
),
'group' => 'jquery.ui',
),
),
'skinStyles' => array(
'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.progressbar.css',
- 'vector' => 'resources/src/jquery.ui-themes/vector/jquery.ui.progressbar.css',
),
'group' => 'jquery.ui',
),
),
'skinStyles' => array(
'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.resizable.css',
- 'vector' => 'resources/src/jquery.ui-themes/vector/jquery.ui.resizable.css',
),
'group' => 'jquery.ui',
),
),
'skinStyles' => array(
'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.selectable.css',
- 'vector' => 'resources/src/jquery.ui-themes/vector/jquery.ui.selectable.css',
),
'group' => 'jquery.ui',
),
),
'skinStyles' => array(
'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.slider.css',
- 'vector' => 'resources/src/jquery.ui-themes/vector/jquery.ui.slider.css',
),
'group' => 'jquery.ui',
),
),
'skinStyles' => array(
'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.tabs.css',
- 'vector' => 'resources/src/jquery.ui-themes/vector/jquery.ui.tabs.css',
),
'group' => 'jquery.ui',
),
'mediawiki.action.edit.editWarning' => array(
'scripts' => 'resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js',
'dependencies' => array(
+ 'jquery.textSelection',
'mediawiki.jqueryMsg'
),
'messages' => array(
'mediawiki.special' => array(
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.js',
'styles' => 'resources/src/mediawiki.special/mediawiki.special.css',
- 'skinStyles' => array(
- 'vector' => 'skins/Vector/special.less', // FIXME this should use $wgStyleDirectory
- ),
),
'mediawiki.special.block' => array(
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.block.js',
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.preferences.js',
'styles' => 'resources/src/mediawiki.special/mediawiki.special.preferences.css',
'position' => 'top',
- 'skinStyles' => array(
- 'vector' => 'skins/Vector/special.preferences.less', // FIXME this should use $wgStyleDirectory
- ),
'messages' => array(
'prefs-tabs-navigation-hint',
),
),
'skinStyles' => array(
'default' => 'resources/lib/oojs-ui/oojs-ui-apex.css',
+ // FIXME As of July 2014, this is to be gone "in a couple of months".
'minerva' => 'resources/lib/oojs-ui/oojs-ui-agora.css',
),
'messages' => array(
-/*jshint eqnull:true */
/*!
- * jQuery Cookie Plugin v1.2
+ * jQuery Cookie Plugin v1.3.1
* https://github.com/carhartl/jquery-cookie
*
- * Copyright 2011, Klaus Hartl
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.opensource.org/licenses/GPL-2.0
+ * Copyright 2013 Klaus Hartl
+ * Released under the MIT license
*/
(function ($, document, undefined) {
}
function decoded(s) {
- return decodeURIComponent(s.replace(pluses, ' '));
+ return unRfc2068(decodeURIComponent(s.replace(pluses, ' ')));
}
- $.cookie = function (key, value, options) {
+ function unRfc2068(value) {
+ if (value.indexOf('"') === 0) {
+ // This is a quoted cookie as according to RFC2068, unescape
+ value = value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
+ }
+ return value;
+ }
+
+ function fromJSON(value) {
+ return config.json ? JSON.parse(value) : value;
+ }
- // key and at least value given, set cookie...
- if (value !== undefined && !/Object/.test(Object.prototype.toString.call(value))) {
- options = $.extend({}, $.cookie.defaults, options);
+ var config = $.cookie = function (key, value, options) {
+
+ // write
+ if (value !== undefined) {
+ options = $.extend({}, config.defaults, options);
if (value === null) {
options.expires = -1;
t.setDate(t.getDate() + days);
}
- value = String(value);
+ value = config.json ? JSON.stringify(value) : String(value);
return (document.cookie = [
- encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value),
+ encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
].join(''));
}
- // key and possibly options given, get cookie...
- options = value || $.cookie.defaults || {};
- var decode = options.raw ? raw : decoded;
+ // read
+ var decode = config.raw ? raw : decoded;
var cookies = document.cookie.split('; ');
- for (var i = 0, parts; (parts = cookies[i] && cookies[i].split('=')); i++) {
- if (decode(parts.shift()) === key) {
- return decode(parts.join('='));
+ var result = key ? null : {};
+ for (var i = 0, l = cookies.length; i < l; i++) {
+ var parts = cookies[i].split('=');
+ var name = decode(parts.shift());
+ var cookie = decode(parts.join('='));
+
+ if (key && key === name) {
+ result = fromJSON(cookie);
+ break;
+ }
+
+ if (!key) {
+ result[name] = fromJSON(cookie);
}
}
- return null;
+ return result;
};
- $.cookie.defaults = {};
+ config.defaults = {};
$.removeCookie = function (key, options) {
- if ($.cookie(key, options) !== null) {
+ if ($.cookie(key) !== null) {
$.cookie(key, null, options);
return true;
}
"QuimGil",
"SMP",
"Vriullop",
- "Toniher"
+ "Toniher",
+ "Edustus"
]
},
"ooui-outline-control-move-down": "Baixa element",
"ooui-outline-control-move-up": "Puja element",
"ooui-toolbar-more": "Més",
- "ooui-dialog-process-dismiss": "Descarta"
+ "ooui-dialog-process-dismiss": "Descarta",
+ "ooui-dialog-process-retry": "Torneu-ho a provar"
}
{
- "@metadata": {
- "authors": [
- "Trevor Parscal",
- "Ed Sanders",
- "James D. Forrester",
- "Raimond Spekking",
- "Erik Moeller",
- "Moriel Schottlender",
- "Yuki Shira",
- "Siebrand Mazeland",
- "Rob Moen",
- "Timo Tijhof",
- "Roan Kattouw",
- "Christian Williams",
- "Amir E. Aharoni"
- ]
- },
- "ooui-outline-control-move-down": "Move item down",
- "ooui-outline-control-move-up": "Move item up",
- "ooui-outline-control-remove": "Remove item",
- "ooui-toolbar-more": "More",
- "ooui-dialog-message-accept": "OK",
- "ooui-dialog-message-reject": "Cancel",
- "ooui-dialog-process-error": "Something went wrong",
- "ooui-dialog-process-dismiss": "Dismiss",
- "ooui-dialog-process-retry": "Try again"
+ "@metadata": {
+ "authors": [
+ "Trevor Parscal",
+ "Ed Sanders",
+ "James D. Forrester",
+ "Raimond Spekking",
+ "Erik Moeller",
+ "Moriel Schottlender",
+ "Yuki Shira",
+ "Siebrand Mazeland",
+ "Rob Moen",
+ "Timo Tijhof",
+ "Roan Kattouw",
+ "Christian Williams",
+ "Amir E. Aharoni"
+ ]
+ },
+ "ooui-outline-control-move-down": "Move item down",
+ "ooui-outline-control-move-up": "Move item up",
+ "ooui-outline-control-remove": "Remove item",
+ "ooui-toolbar-more": "More",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Cancel",
+ "ooui-dialog-process-error": "Something went wrong",
+ "ooui-dialog-process-dismiss": "Dismiss",
+ "ooui-dialog-process-retry": "Try again"
}
"Njardarlogar"
]
},
- "ooui-dialog-action-close": "Lukk",
"ooui-outline-control-move-down": "Flytt ned",
"ooui-outline-control-move-up": "Flytt opp",
"ooui-outline-control-remove": "Fjern element",
- "ooui-toolbar-more": "Mer"
+ "ooui-toolbar-more": "Mer",
+ "ooui-dialog-message-reject": "Avbryt",
+ "ooui-dialog-process-error": "Noe gikk galt",
+ "ooui-dialog-process-dismiss": "Lukk",
+ "ooui-dialog-process-retry": "Prøv igjen"
}
"Yerpo"
]
},
- "ooui-dialog-action-close": "Zapri",
"ooui-outline-control-move-down": "Prestavi predmet nižje",
"ooui-outline-control-move-up": "Prestavi predmet višje",
"ooui-outline-control-remove": "Odstrani vnos",
"ooui-toolbar-more": "Več",
- "ooui-dialog-confirm-title": "Potrdi",
- "ooui-dialog-confirm-default-prompt": "Ste prepričani?",
- "ooui-dialog-confirm-default-ok": "V redu",
- "ooui-dialog-confirm-default-cancel": "Prekliči"
+ "ooui-dialog-message-accept": "V redu",
+ "ooui-dialog-message-reject": "Prekliči",
+ "ooui-dialog-process-error": "Nekaj je šlo narobe",
+ "ooui-dialog-process-dismiss": "Skrij",
+ "ooui-dialog-process-retry": "Poskusi znova"
}
"Maidis",
"Rapsar",
"Talha Samil Cakir",
- "TurkishStyles"
+ "TurkishStyles",
+ "Sayginer"
]
},
- "ooui-dialog-action-close": "Kapat",
"ooui-outline-control-move-down": "Ögeyi aşağı taşı",
"ooui-outline-control-move-up": "Ögeyi yukarı taşı",
- "ooui-toolbar-more": "Daha fazla"
+ "ooui-toolbar-more": "Daha fazla",
+ "ooui-dialog-process-retry": "Tekrar dene"
}
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- width="15px" height="8px" viewBox="0 0 15 8" style="enable-background:new 0 0 15 8;" xml:space="preserve">
-<g id="anchor">
- <polygon id="outline" style="fill-rule:evenodd;clip-rule:evenodd;fill:#808080;" points="7.609,2.499 2.096,8 13.125,8"/>
- <polygon id="fill" style="fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;" points="7.609,3 2.598,8 12.622,8"/>
-</g>
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="15" height="8" viewBox="0 0 15 8">
+ <g id="anchor">
+ <polygon id="outline" style="fill:#808080;" points="7.609,2.499 2.096,8 13.125,8"/>
+ <polygon id="fill" style="fill:#FFFFFF;" points="7.609,3 2.598,8 12.622,8"/>
+ </g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="apply" opacity=".75">
- <path id="check" fill-rule="evenodd" clip-rule="evenodd" d="M19.062 5.139l-1.644-1.139-8.551 12.357-3.454-3.454-1.413 1.413 5.021 5.022z"/>
+ <g id="accept" opacity=".75">
+ <path id="check" d="M19.062 5.139l-1.644-1.139-8.551 12.357-3.454-3.454-1.413 1.413 5.021 5.022z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="apply" opacity=".75">
- <path d="M13 8h-2v3h-3v2h3v3h2v-3h3v-2h-3z"/>
+ <g id="add-item" opacity=".75">
+ <path id="plus" d="M13 8h-2v3h-3v2h3v3h2v-3h3v-2h-3z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="settings" opacity=".75">
- <path id="gear" d="M20.869 13.476c.079-.482.131-.972.131-1.476s-.052-.994-.131-1.476l-2.463-.259c-.149-.556-.367-1.082-.648-1.57l1.558-1.924c-.576-.806-1.281-1.511-2.087-2.087l-1.924 1.558c-.488-.281-1.015-.499-1.57-.648l-.259-2.463c-.482-.079-.972-.131-1.476-.131s-.994.052-1.476.131l-.259 2.463c-.555.149-1.081.367-1.57.648l-1.924-1.557c-.805.576-1.51 1.281-2.086 2.086l1.558 1.924c-.281.488-.499 1.015-.648 1.57l-2.463.259c-.08.482-.132.972-.132 1.476s.052.994.131 1.476l2.463.259c.149.556.367 1.082.648 1.57l-1.558 1.924c.576.806 1.281 1.511 2.087 2.087l1.924-1.558c.488.281 1.015.499 1.57.648l.259 2.463c.482.079.972.131 1.476.131s.994-.052 1.476-.131l.259-2.463c.556-.149 1.082-.367 1.57-.648l1.924 1.558c.806-.576 1.511-1.281 2.087-2.087l-1.558-1.924c.281-.488.499-1.015.648-1.57l2.463-.259zm-8.869 2.522c-2.209 0-3.998-1.789-3.998-3.998s1.789-3.998 3.998-3.998 3.998 1.789 3.998 3.998-1.789 3.998-3.998 3.998z" fill-rule="evenodd" clip-rule="evenodd"/>
+ <path id="gear" d="M20.869 13.476c.079-.482.131-.972.131-1.476s-.052-.994-.131-1.476l-2.463-.259c-.149-.556-.367-1.082-.648-1.57l1.558-1.924c-.576-.806-1.281-1.511-2.087-2.087l-1.924 1.558c-.488-.281-1.015-.499-1.57-.648l-.259-2.463c-.482-.079-.972-.131-1.476-.131s-.994.052-1.476.131l-.259 2.463c-.555.149-1.081.367-1.57.648l-1.924-1.557c-.805.576-1.51 1.281-2.086 2.086l1.558 1.924c-.281.488-.499 1.015-.648 1.57l-2.463.259c-.08.482-.132.972-.132 1.476s.052.994.131 1.476l2.463.259c.149.556.367 1.082.648 1.57l-1.558 1.924c.576.806 1.281 1.511 2.087 2.087l1.924-1.558c.488.281 1.015.499 1.57.648l.259 2.463c.482.079.972.131 1.476.131s.994-.052 1.476-.131l.259-2.463c.556-.149 1.082-.367 1.57-.648l1.924 1.558c.806-.576 1.511-1.281 2.087-2.087l-1.558-1.924c.281-.488.499-1.015.648-1.57l2.463-.259zm-8.869 2.522c-2.209 0-3.998-1.789-3.998-3.998s1.789-3.998 3.998-3.998 3.998 1.789 3.998 3.998-1.789 3.998-3.998 3.998z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="alert" opacity=".75">
- <path id="point" fill-rule="evenodd" clip-rule="evenodd" d="M11 16h2v2h-2z"/>
- <path id="stroke" fill-rule="evenodd" clip-rule="evenodd" d="M13.516 10h-3l.484 5h2z"/>
+ <path id="point" d="M11 16h2v2h-2z"/>
+ <path id="stroke" d="M13.516 10h-3l.484 5h2z"/>
<path id="triangle" d="M12.017 5.974l7.519 13.026h-15.04l7.521-13.026m0-2.474c-.544 0-1.088.357-1.5 1.071l-7.985 13.831c-.825 1.429-.15 2.598 1.5 2.598h15.968c1.65 0 2.325-1.169 1.5-2.599l-7.983-13.829c-.413-.715-.956-1.072-1.5-1.072z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="arched-arrow-ltr" opacity=".75">
- <path id="arrow" d="M19.925 14.937l-2.391-6.901-1.48 2.329c-.964-.845-2.699-1.85-5.513-1.823-4.887.046-6.524 4.244-6.524 4.244s2.753-2.639 6.925-1.949c1.729.286 3.007 1.206 3.675 1.791l-1.474 2.319 6.782-.01z" fill-rule="evenodd" clip-rule="evenodd"/>
+ <path id="arrow" d="M19.925 14.937l-2.391-6.901-1.48 2.329c-.964-.845-2.699-1.85-5.513-1.823-4.887.046-6.524 4.244-6.524 4.244s2.753-2.639 6.925-1.949c1.729.286 3.007 1.206 3.675 1.791l-1.474 2.319 6.782-.01z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="arched-arrow-rtl" opacity=".75">
- <path id="arrow" d="M13.401 8.542c-2.814-.027-4.549.978-5.513 1.823l-1.48-2.329-2.391 6.901 6.782.009-1.474-2.319c.668-.584 1.945-1.504 3.675-1.791 4.172-.69 6.925 1.949 6.925 1.949s-1.637-4.197-6.524-4.243z" fill-rule="evenodd" clip-rule="evenodd"/>
+ <path id="arrow" d="M13.401 8.542c-2.814-.027-4.549.978-5.513 1.823l-1.48-2.329-2.391 6.901 6.782.009-1.474-2.319c.668-.584 1.945-1.504 3.675-1.791 4.172-.69 6.925 1.949 6.925 1.949s-1.637-4.197-6.524-4.243z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="clear" opacity=".75">
- <path id="circle_with_strike" d="M11.999 5.022c-3.853 0-6.977 3.124-6.977 6.978 0 3.853 3.124 6.978 6.977 6.978 3.854 0 6.979-3.125 6.979-6.978 0-3.854-3.125-6.978-6.979-6.978zm-5.113 6.978c0-1.092.572-3.25.93-2.929l7.113 7.113c.488.525-1.837.931-2.93.931-2.825-.001-5.113-2.291-5.113-5.115zm9.298 2.929l-7.114-7.113c-.445-.483 1.837-.931 2.929-.931 2.827 0 5.115 2.289 5.115 5.114 0 1.093-.364 3.543-.93 2.93z" fill-rule="evenodd" clip-rule="evenodd"/>
+ <path id="circle-with-strike" d="M11.999 5.022c-3.853 0-6.977 3.124-6.977 6.978 0 3.853 3.124 6.978 6.977 6.978 3.854 0 6.979-3.125 6.979-6.978 0-3.854-3.125-6.978-6.979-6.978zm-5.113 6.978c0-1.092.572-3.25.93-2.929l7.113 7.113c.488.525-1.837.931-2.93.931-2.825-.001-5.113-2.291-5.113-5.115zm9.298 2.929l-7.114-7.113c-.445-.483 1.837-.931 2.929-.931 2.827 0 5.115 2.289 5.115 5.114 0 1.093-.364 3.543-.93 2.93z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="close" opacity=".75">
- <path id="x" fill-rule="evenodd" clip-rule="evenodd" d="M18.717 6.697l-1.414-1.414-5.303 5.303-5.303-5.303-1.414 1.414 5.303 5.303-5.303 5.303 1.414 1.414 5.303-5.303 5.303 5.303 1.414-1.414-5.303-5.303z"/>
+ <path id="x" d="M18.717 6.697l-1.414-1.414-5.303 5.303-5.303-5.303-1.414 1.414 5.303 5.303-5.303 5.303 1.414 1.414 5.303-5.303 5.303 5.303 1.414-1.414-5.303-5.303z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="collapse" opacity=".75">
- <path id="arrow" fill-rule="evenodd" clip-rule="evenodd" d="M6.697 15.714l5.303-5.302 5.303 5.302 1.414-1.414-6.717-6.717-6.717 6.717z"/>
+ <path id="arrow" d="M6.697 15.714l5.303-5.302 5.303 5.302 1.414-1.414-6.717-6.717-6.717 6.717z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="comment" opacity=".75">
- <path id="speech_bubble" d="M15 6h-6c-1.657 0-3 1.344-3 3v4c0 1.656 1.343 3 3 3v3l3-3h3c1.657 0 3-1.344 3-3v-4c0-1.656-1.343-3-3-3z" fill-rule="evenodd" clip-rule="evenodd"/>
+ <path id="speech-bubble" d="M15 6h-6c-1.657 0-3 1.344-3 3v4c0 1.656 1.343 3 3 3v3l3-3h3c1.657 0 3-1.344 3-3v-4c0-1.656-1.343-3-3-3z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="expand" opacity=".75">
- <path id="arrow" fill-rule="evenodd" clip-rule="evenodd" d="M17.303 8.283l-5.303 5.303-5.303-5.303-1.414 1.414 6.717 6.717 6.717-6.717z"/>
+ <path id="arrow" d="M17.303 8.283l-5.303 5.303-5.303-5.303-1.414 1.414 6.717 6.717 6.717-6.717z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="help" opacity=".75" fill-rule="evenodd" clip-rule="evenodd">
+ <g id="help" opacity=".75">
<path id="circle" d="M12.001 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 5.476 4.438 9.914 9.916 9.914 5.476 0 9.914-4.438 9.914-9.914 0-5.478-4.438-9.916-9.914-9.916zm.001 18c-4.465 0-8.084-3.619-8.084-8.083 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083z"/>
- <g id="question_mark">
+ <g id="question-mark">
<path id="top" d="M11.766 6.688c-2.5 0-3.219 2.188-3.219 2.188l1.411.854s.298-.791.901-1.229c.516-.375 1.625-.625 2.219.125.701.885-.17 1.587-1.078 2.719-.953 1.186-1 3.655-1 3.655h1.969s.135-2.318 1.041-3.381c.603-.707 1.443-1.338 1.443-2.494s-1.187-2.437-3.687-2.437z"/>
<path id="bottom" d="M11 16h2v2h-2z"/>
</g>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="history" opacity=".75" fill-rule="evenodd" clip-rule="evenodd">
- <path id="clock_hands" d="M17.26 15.076s-2.385-1.935-4.005-3.062c.72-2.397 1.702-6.559 1.702-6.559s-4.35 5.363-4.877 6.699c-.463 1.168 1.459 2.209 2.346 1.678 1.9.551 4.834 1.244 4.834 1.244z"/>
+ <g id="history" opacity=".75">
+ <path id="clock-hands" d="M17.26 15.076s-2.385-1.935-4.005-3.062c.72-2.397 1.702-6.559 1.702-6.559s-4.35 5.363-4.877 6.699c-.463 1.168 1.459 2.209 2.346 1.678 1.9.551 4.834 1.244 4.834 1.244z"/>
<path id="arrow" d="M12.086 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 1.783.476 3.454 1.301 4.898l-2.223 2.04h5.688v-5.219l-2.066 1.896c-.55-1.088-.866-2.312-.866-3.615 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083-1.145 0-2.228-.247-3.213-.678l-.833 1.634c1.235.557 2.602.874 4.045.874 5.476 0 9.914-4.438 9.914-9.914-.001-5.477-4.439-9.915-9.915-9.915z"/>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0, 0, 24, 24">
- <g id="help" opacity=".75">
- <path d="M11.499 17c-3.036 0-5.499-2.464-5.499-5.5 0-3.037 2.462-5.5 5.499-5.5 3.037 0 5.501 2.462 5.501 5.5 0 3.036-2.464 5.5-5.501 5.5zm.002-12c-3.591 0-6.501 2.91-6.501 6.5s2.91 6.5 6.501 6.5c3.588 0 6.499-2.911 6.499-6.5s-2.911-6.5-6.499-6.5zM12 10v4h1v1h-3v-1h1v-3h-1v-1zM11 8h1v1h-1z"/>
+ <g id="info" opacity=".75">
+ <path id="circled-i" d="M11.499 17c-3.036 0-5.499-2.464-5.499-5.5 0-3.037 2.462-5.5 5.499-5.5 3.037 0 5.501 2.462 5.501 5.5 0 3.036-2.464 5.5-5.501 5.5zm.002-12c-3.591 0-6.501 2.91-6.501 6.5s2.91 6.5 6.501 6.5c3.588 0 6.499-2.911 6.499-6.5s-2.911-6.5-6.499-6.5zM12 10v4h1v1h-3v-1h1v-3h-1v-1zM11 8h1v1h-1z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="link" opacity=".75">
<path id="right" d="M19.188 12.001c0 1.1-.891 2.015-1.988 2.015l-4.195-.015c.538 1.088.963 1.999 1.997 1.999h3c1.656 0 2.998-2.343 2.998-4s-1.342-4-2.998-4h-3c-1.034 0-1.459.911-1.998 1.999l4.195-.015c1.098 0 1.989.917 1.989 2.017z"/>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="menu" opacity=".75">
<path id="lines" d="M6 15h12c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1h-12c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1zm-1-4v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1h-12c-.553 0-1 .447-1 1zm0-5v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1h-12c-.553 0-1 .447-1 1z"/>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="move-ltr" opacity=".75">
- <path id="arrow" fill-rule="evenodd" clip-rule="evenodd" d="M8.935 7.181l5.302 5.302-5.302 5.303 1.414 1.414 6.716-6.717-6.716-6.716z"/>
+ <path id="arrow" d="M8.935 7.181l5.302 5.302-5.302 5.303 1.414 1.414 6.716-6.717-6.716-6.716z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="move-rtl" opacity=".75">
- <path id="arrow_9_" fill-rule="evenodd" clip-rule="evenodd" d="M15.065 17.786l-5.302-5.303 5.302-5.302-1.414-1.414-6.716 6.716 6.716 6.717z"/>
+ <path id="arrow" d="M15.065 17.786l-5.302-5.303 5.302-5.302-1.414-1.414-6.716 6.716 6.716 6.717z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="picture" opacity=".75" fill-rule="evenodd" clip-rule="evenodd">
+ <g id="picture" opacity=".75">
<path id="frame" d="M18 4h-12c-2-.007-3 .993-3 2.993l.014 9.007c-.014 2 .986 2.988 2.986 3h12c2-.012 2.994-1 3-3.006v-9.001c-.006-2-1-3-3-2.993zm1 13h-14v-11h14v11z"/>
<path id="mountains" d="M6 13.5l3.5-3.5 2.328 2.312-1.312 1.094.875 1.032 4.109-3.438 2.5 2v3h-12z"/>
<path id="sky" d="M6 12l3.516-4.156 3.046 3.172 2.938-2.016 2.5 2v-4h-12z"/>
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0, 0, 24, 24">
<g id="remove-item">
- <path d="M8 11h8v2h-8z"/>
+ <path id="minus" d="M8 11h8v2h-8z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="remove" opacity=".75">
- <path id="trash_can" d="M12 10h-1v6h1v-6zm-2 0h-1v6h1v-6zm4 0h-1v6h1v-6zm0-4v-1h-5v1h-3v3h1v7.966l1 1.031v-.074.077h6.984l.016-.018v.015l1-1.031v-7.966h1v-3h-3zm1 11h-7v-8h7v8zm1-9h-9v-1h9v1z" fill-rule="evenodd" clip-rule="evenodd"/>
+ <path id="trash-can" d="M12 10h-1v6h1v-6zm-2 0h-1v6h1v-6zm4 0h-1v6h1v-6zm0-4v-1h-5v1h-3v3h1v7.966l1 1.031v-.074.077h6.984l.016-.018v.015l1-1.031v-7.966h1v-3h-3zm1 11h-7v-8h7v8zm1-9h-9v-1h9v1z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="search" opacity=".75">
- <path id="magnifying_glass" d="M16.021 15.96l-2.374-2.375-.169-.099c.403-.566.643-1.26.643-2.009-.001-1.92-1.558-3.477-3.477-3.477-1.921 0-3.478 1.557-3.478 3.478 0 1.92 1.557 3.477 3.478 3.477.749 0 1.442-.239 2.01-.643l.098.169 2.375 2.374c.19.189.543.143.79-.104s.293-.601.104-.791zm-5.377-2.27c-1.221 0-2.213-.991-2.213-2.213 0-1.221.992-2.213 2.213-2.213 1.222 0 2.213.992 2.213 2.213-.001 1.222-.992 2.213-2.213 2.213z"/>
+ <path id="magnifying-glass" d="M16.021 15.96l-2.374-2.375-.169-.099c.403-.566.643-1.26.643-2.009-.001-1.92-1.558-3.477-3.477-3.477-1.921 0-3.478 1.557-3.478 3.478 0 1.92 1.557 3.477 3.478 3.477.749 0 1.442-.239 2.01-.643l.098.169 2.375 2.374c.19.189.543.143.79-.104s.293-.601.104-.791zm-5.377-2.27c-1.221 0-2.213-.991-2.213-2.213 0-1.221.992-2.213 2.213-2.213 1.222 0 2.213.992 2.213 2.213-.001 1.222-.992 2.213-2.213 2.213z"/>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0, 0, 24, 24">
<g id="settings" opacity=".75">
- <path d="M3 4h3v2h-3zM12 4h9v2h-9zM8 3h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 11h9v2h-9zM18 11h3v2h-3zM14 10h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 18h6v2h-6zM15 18h6v2h-6zM11 17h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1z"/>
+ <path id="gear" d="M3 4h3v2h-3zM12 4h9v2h-9zM8 3h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 11h9v2h-9zM18 11h3v2h-3zM14 10h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 18h6v2h-6zM15 18h6v2h-6zM11 17h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="tag" opacity=".75">
<path d="M18.748 11.717c.389.389.389 1.025 0 1.414l-4.949 4.95c-.389.389-1.025.389-1.414 0l-6.01-6.01c-.389-.389-.707-1.157-.707-1.707l-.001-4.364c0-.55.45-1 1-1h4.364c.55 0 1.318.318 1.707.707l6.01 6.01zm-10.644-4.261c-.579.576-.578 1.514-.001 2.093.578.577 1.516.577 2.095.001.576-.578.576-1.517 0-2.095-.581-.576-1.518-.577-2.094.001z"/>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="window" opacity=".75">
<path id="title" d="M7 10h10v1h-10z"/>
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="deprecated" opacity=".75">
+ <g id="alert" opacity=".75">
<path d="M6 12c-3.314 0-6-2.686-6-6s2.686-6 6-6 6 2.686 6 6-2.686 6-6 6zm-1-5h2v-5h-2zm0 3h2v-2h-2z"/>
</g>
</svg>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
<g id="down" opacity=".75">
<path id="arrow" d="M2 3l3.5 6 3.5-6z"/>
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
<g id="up" opacity=".75">
<path id="arrow" d="M5.5 2l-3.5 6h7z"/>
/*!
- * OOjs UI v0.1.0-pre (a7ce4d48d9)
+ * OOjs UI v0.1.0-pre (e9cf571db2)
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2014 OOjs Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2014-07-23T23:48:16Z
+ * Date: 2014-07-28T21:48:00Z
*/
.oo-ui-dialog-content > .oo-ui-window-head,
.oo-ui-dialog-content > .oo-ui-window-body,
/*!
- * OOjs UI v0.1.0-pre (a7ce4d48d9)
+ * OOjs UI v0.1.0-pre (e9cf571db2)
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2014 OOjs Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2014-07-23T23:48:16Z
+ * Date: 2014-07-28T21:48:00Z
*/
.oo-ui-dialog-content > .oo-ui-window-head,
.oo-ui-dialog-content > .oo-ui-window-body,
/*!
- * OOjs UI v0.1.0-pre (a7ce4d48d9)
+ * OOjs UI v0.1.0-pre (e9cf571db2)
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2014 OOjs Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2014-07-23T23:48:16Z
+ * Date: 2014-07-28T21:48:00Z
*/
( function ( OO ) {
* @property {Object}
*/
OO.ui.Keys = {
- 'UNDEFINED': 0,
- 'BACKSPACE': 8,
- 'DELETE': 46,
- 'LEFT': 37,
- 'RIGHT': 39,
- 'UP': 38,
- 'DOWN': 40,
- 'ENTER': 13,
- 'END': 35,
- 'HOME': 36,
- 'TAB': 9,
- 'PAGEUP': 33,
- 'PAGEDOWN': 34,
- 'ESCAPE': 27,
- 'SHIFT': 16,
- 'SPACE': 32
+ UNDEFINED: 0,
+ BACKSPACE: 8,
+ DELETE: 46,
+ LEFT: 37,
+ RIGHT: 39,
+ UP: 38,
+ DOWN: 40,
+ ENTER: 13,
+ END: 35,
+ HOME: 36,
+ TAB: 9,
+ PAGEUP: 33,
+ PAGEDOWN: 34,
+ ESCAPE: 27,
+ SHIFT: 16,
+ SPACE: 32
};
/**
// Properties
this.list = [];
this.categories = {
- 'actions': 'getAction',
- 'flags': 'getFlags',
- 'modes': 'getModes'
+ actions: 'getAction',
+ flags: 'getFlags',
+ modes: 'getModes'
};
this.categorized = {};
this.special = {};
for ( i = 0, len = actions.length; i < len; i++ ) {
action = actions[i];
action.connect( this, {
- 'click': [ 'emit', 'click', action ],
- 'resize': [ 'emit', 'resize', action ],
- 'toggle': [ 'onActionChange' ]
+ click: [ 'emit', 'click', action ],
+ resize: [ 'emit', 'resize', action ],
+ toggle: [ 'onActionChange' ]
} );
this.list.push( action );
}
to = window;
}
if ( !offset ) {
- offset = { 'top': 0, 'left': 0 };
+ offset = { top: 0, left: 0 };
}
if ( from.parent === from ) {
return offset;
OO.ui.Element.getRelativePosition = function ( $from, $to ) {
var from = $from.offset(),
to = $to.offset();
- return { 'top': Math.round( from.top - to.top ), 'left': Math.round( from.left - to.left ) };
+ return { top: Math.round( from.top - to.top ), left: Math.round( from.left - to.left ) };
};
/**
right = parseFloat( style ? style.borderRightWidth : $el.css( 'borderRightWidth' ) ) || 0;
return {
- 'top': Math.round( top ),
- 'left': Math.round( left ),
- 'bottom': Math.round( bottom ),
- 'right': Math.round( right )
+ top: Math.round( top ),
+ left: Math.round( left ),
+ bottom: Math.round( bottom ),
+ right: Math.round( right )
};
};
if ( win === el || el === doc.documentElement ) {
$win = $( win );
return {
- 'borders': { 'top': 0, 'left': 0, 'bottom': 0, 'right': 0 },
- 'scroll': {
- 'top': $win.scrollTop(),
- 'left': $win.scrollLeft()
+ borders: { top: 0, left: 0, bottom: 0, right: 0 },
+ scroll: {
+ top: $win.scrollTop(),
+ left: $win.scrollLeft()
},
- 'scrollbar': { 'right': 0, 'bottom': 0 },
- 'rect': {
- 'top': 0,
- 'left': 0,
- 'bottom': $win.innerHeight(),
- 'right': $win.innerWidth()
+ scrollbar: { right: 0, bottom: 0 },
+ rect: {
+ top: 0,
+ left: 0,
+ bottom: $win.innerHeight(),
+ right: $win.innerWidth()
}
};
} else {
$el = $( el );
return {
- 'borders': this.getBorders( el ),
- 'scroll': {
- 'top': $el.scrollTop(),
- 'left': $el.scrollLeft()
+ borders: this.getBorders( el ),
+ scroll: {
+ top: $el.scrollTop(),
+ left: $el.scrollLeft()
},
- 'scrollbar': {
- 'right': $el.innerWidth() - el.clientWidth,
- 'bottom': $el.innerHeight() - el.clientHeight
+ scrollbar: {
+ right: $el.innerWidth() - el.clientWidth,
+ bottom: $el.innerHeight() - el.clientHeight
},
- 'rect': el.getBoundingClientRect()
+ rect: el.getBoundingClientRect()
};
}
};
if ( $sc.is( 'body' ) ) {
// If the scrollable container is the <body> this is easy
rel = {
- 'top': eld.rect.top,
- 'bottom': $win.innerHeight() - eld.rect.bottom,
- 'left': eld.rect.left,
- 'right': $win.innerWidth() - eld.rect.right
+ top: eld.rect.top,
+ bottom: $win.innerHeight() - eld.rect.bottom,
+ left: eld.rect.left,
+ right: $win.innerWidth() - eld.rect.right
};
} else {
// Otherwise, we have to subtract el's coordinates from sc's coordinates
rel = {
- 'top': eld.rect.top - ( scd.rect.top + scd.borders.top ),
- 'bottom': scd.rect.bottom - scd.borders.bottom - scd.scrollbar.bottom - eld.rect.bottom,
- 'left': eld.rect.left - ( scd.rect.left + scd.borders.left ),
- 'right': scd.rect.right - scd.borders.right - scd.scrollbar.right - eld.rect.right
+ top: eld.rect.top - ( scd.rect.top + scd.borders.top ),
+ bottom: scd.rect.bottom - scd.borders.bottom - scd.scrollbar.bottom - eld.rect.bottom,
+ left: eld.rect.left - ( scd.rect.left + scd.borders.left ),
+ right: scd.rect.right - scd.borders.right - scd.scrollbar.right - eld.rect.right
};
}
// Initialize
this.$element
.addClass( 'oo-ui-frame' )
- .attr( { 'frameborder': 0, 'scrolling': 'no' } );
+ .attr( { frameborder: 0, scrolling: 'no' } );
};
* @chainable
*/
OO.ui.Frame.prototype.setSize = function ( width, height ) {
- this.$element.css( { 'width': width, 'height': height } );
+ this.$element.css( { width: width, height: height } );
return this;
};
*/
OO.ui.Widget = function OoUiWidget( config ) {
// Initialize config
- config = $.extend( { 'disabled': false }, config );
+ config = $.extend( { disabled: false }, config );
// Parent constructor
OO.ui.Widget.super.call( this, config );
this.opened = null;
this.timing = null;
this.size = config.size || this.constructor.static.size;
- this.frame = new OO.ui.Frame( { '$': this.$ } );
+ this.frame = new OO.ui.Frame( { $: this.$ } );
this.$frame = this.$( '<div>' );
this.$ = function () {
throw new Error( 'this.$() cannot be used until the frame has been initialized.' );
OO.ui.Window.prototype.setDimensions = function ( dim ) {
// Apply width before height so height is not based on wrapping content using the wrong width
this.$frame.css( {
- 'width': dim.width || '',
- 'min-width': dim.minWidth || '',
- 'max-width': dim.maxWidth || ''
+ width: dim.width || '',
+ minWidth: dim.minWidth || '',
+ maxWidth: dim.maxWidth || ''
} );
this.$frame.css( {
- 'height': ( dim.height !== undefined ? dim.height : this.getContentHeight() ) || '',
- 'min-height': dim.minHeight || '',
- 'max-height': dim.maxHeight || ''
+ height: ( dim.height !== undefined ? dim.height : this.getContentHeight() ) || '',
+ minHeight: dim.minHeight || '',
+ maxHeight: dim.maxHeight || ''
} );
return this;
};
// Events
this.actions.connect( this, {
- 'click': 'onActionClick',
- 'resize': 'onActionResize',
- 'change': 'onActionsChange'
+ click: 'onActionClick',
+ resize: 'onActionResize',
+ change: 'onActionsChange'
} );
// Initialization
);
for ( i = 0, len = actions.length; i < len; i++ ) {
items.push(
- new OO.ui.ActionWidget( $.extend( { '$': this.$ }, actions[i] ) )
+ new OO.ui.ActionWidget( $.extend( { $: this.$ }, actions[i] ) )
);
}
this.actions.add( items );
OO.ui.Dialog.super.prototype.initialize.call( this );
// Properties
- this.title = new OO.ui.LabelWidget( { '$': this.$ } );
+ this.title = new OO.ui.LabelWidget( { $: this.$ } );
// Events
if ( this.constructor.static.escapable ) {
*
* - {@link #closeWindow} or {@link OO.ui.Window#close} methods are used to start closing
* - `opened` promise is resolved with `closing` promise
- * - {@link #event-opening} is emitted with `closing` promise
+ * - {@link #event-closing} is emitted with `closing` promise
* - {@link #getHoldDelay} is called the returned value is used to time a pause in execution
* - {@link OO.ui.Window#getHoldProcess} method is called on the window and its result executed
* - `hold` progress notification is emitted from opening promise
* @property {Object}
*/
OO.ui.WindowManager.static.sizes = {
- 'small': {
- 'width': 300
+ small: {
+ width: 300
},
- 'medium': {
- 'width': 500
+ medium: {
+ width: 500
},
- 'large': {
- 'width': 700
+ large: {
+ width: 700
},
- 'full': {
+ full: {
// These can be non-numeric because they are never used in calculations
- 'width': '100%',
- 'height': '100%'
+ width: '100%',
+ height: '100%'
}
};
'Cannot auto-instantiate window: symbolic name is unrecognized by the factory'
) );
} else {
- win = this.factory.create( name, this, { '$': this.$ } );
+ win = this.factory.create( name, this, { $: this.$ } );
this.addWindows( [ win ] ).then(
OO.ui.bind( deferred.resolve, deferred, win ),
deferred.reject
if ( manager.modal ) {
manager.$( manager.getElementDocument() ).on( {
// Prevent scrolling by keys in top-level window
- 'keydown': manager.onDocumentKeyDownHandler
+ keydown: manager.onDocumentKeyDownHandler
} );
manager.$( manager.getElementWindow() ).on( {
// Prevent scrolling by wheel in top-level window
- 'mousewheel': manager.onWindowMouseWheelHandler,
+ mousewheel: manager.onWindowMouseWheelHandler,
// Start listening for top-level window dimension changes
'orientationchange resize': manager.onWindowResizeHandler
} );
manager.updateWindowSize( win );
setTimeout( function () {
win.setup( data ).then( function () {
- manager.opening.notify( { 'state': 'setup' } );
+ manager.opening.notify( { state: 'setup' } );
setTimeout( function () {
win.ready( data ).then( function () {
- manager.opening.notify( { 'state': 'ready' } );
+ manager.opening.notify( { state: 'ready' } );
manager.opening = null;
manager.opened = $.Deferred();
opening.resolve( manager.opened.promise(), data );
opened.resolve( closing.promise(), data );
setTimeout( function () {
win.hold( data ).then( function () {
- closing.notify( { 'state': 'hold' } );
+ closing.notify( { state: 'hold' } );
setTimeout( function () {
win.teardown( data ).then( function () {
- closing.notify( { 'state': 'teardown' } );
+ closing.notify( { state: 'teardown' } );
if ( manager.modal ) {
manager.$( manager.getElementDocument() ).off( {
// Allow scrolling by keys in top-level window
- 'keydown': manager.onDocumentKeyDownHandler
+ keydown: manager.onDocumentKeyDownHandler
} );
manager.$( manager.getElementWindow() ).off( {
// Allow scrolling by wheel in top-level window
- 'mousewheel': manager.onWindowMouseWheelHandler,
+ mousewheel: manager.onWindowMouseWheelHandler,
// Stop listening for top-level window dimension changes
'orientationchange resize': manager.onWindowResizeHandler
} );
OO.ui.Process.prototype.createStep = function ( step, context ) {
if ( typeof step === 'number' || $.isFunction( step.promise ) ) {
return {
- 'callback': function () {
+ callback: function () {
return step;
},
- 'context': null
+ context: null
};
}
if ( $.isFunction( step ) ) {
return {
- 'callback': step,
- 'context': context
+ callback: step,
+ context: context
};
}
throw new Error( 'Cannot create process step: number, promise or function expected' );
*
* Tools can be specified in the following ways:
*
- * - A specific tool: `{ 'name': 'tool-name' }` or `'tool-name'`
- * - All tools in a group: `{ 'group': 'group-name' }`
+ * - A specific tool: `{ name: 'tool-name' }` or `'tool-name'`
+ * - All tools in a group: `{ group: 'group-name' }`
* - All tools: `'*'`
*
* @private
item = collection[i];
// Allow plain strings as shorthand for named tools
if ( typeof item === 'string' ) {
- item = { 'name': item };
+ item = { name: item };
}
if ( OO.isPlainObject( item ) ) {
if ( item.group ) {
var buffer = 10,
cOffset = this.$clippable.offset(),
$container = this.$clippableContainer.is( 'body' ) ? this.$clippableWindow : this.$clippableContainer,
- ccOffset = $container.offset() || { 'top': 0, 'left': 0 },
+ ccOffset = $container.offset() || { top: 0, left: 0 },
ccHeight = $container.innerHeight() - buffer,
ccWidth = $container.innerWidth() - buffer,
scrollTop = this.$clippableScroller.scrollTop(),
clipHeight = desiredHeight < naturalHeight;
if ( clipWidth ) {
- this.$clippable.css( { 'overflow-x': 'auto', 'width': desiredWidth } );
+ this.$clippable.css( { overflowX: 'auto', width: desiredWidth } );
} else {
this.$clippable.css( 'width', this.idealWidth || '' );
this.$clippable.width(); // Force reflow for https://code.google.com/p/chromium/issues/detail?id=387290
- this.$clippable.css( 'overflow-x', '' );
+ this.$clippable.css( 'overflowX', '' );
}
if ( clipHeight ) {
- this.$clippable.css( { 'overflow-y': 'auto', 'height': desiredHeight } );
+ this.$clippable.css( { overflowY: 'auto', height: desiredHeight } );
} else {
this.$clippable.css( 'height', this.idealHeight || '' );
this.$clippable.height(); // Force reflow for https://code.google.com/p/chromium/issues/detail?id=387290
- this.$clippable.css( 'overflow-y', '' );
+ this.$clippable.css( 'overflowY', '' );
}
this.clipped = clipWidth || clipHeight;
* additional icon names keyed by language code.
*
* Example of i18n icon definition:
- * { 'default': 'bold-a', 'en': 'bold-b', 'de': 'bold-f' }
+ * { default: 'bold-a', en: 'bold-b', de: 'bold-f' }
*
* @static
* @inheritable
// Initialization
this.$indicator.addClass( 'oo-ui-indicatedElement-indicator' );
this.setIndicator( config.indicator || this.constructor.static.indicator );
- this.setIndicatorTitle( config.indicatorTitle || this.constructor.static.indicatorTitle );
+ this.setIndicatorTitle( config.indicatorTitle || this.constructor.static.indicatorTitle );
};
/* Setup */
*/
OO.ui.LabeledElement.prototype.fitLabel = function () {
if ( this.$label.autoEllipsis && this.autoFitLabel ) {
- this.$label.autoEllipsis( { 'hasSpan': false, 'tooltip': true } );
+ this.$label.autoEllipsis( { hasSpan: false, tooltip: true } );
}
return this;
};
// Properties
this.popup = new OO.ui.PopupWidget( $.extend(
- { 'autoClose': true },
+ { autoClose: true },
config.popup,
- { '$': this.$, '$autoCloseIgnore': this.$element }
+ { $: this.$, $autoCloseIgnore: this.$element }
) );
};
this.title = null;
// Events
- this.toolbar.connect( this, { 'updateState': 'onUpdateState' } );
+ this.toolbar.connect( this, { updateState: 'onUpdateState' } );
// Initialization
this.$title.addClass( 'oo-ui-tool-title' );
*
* Tools can be specified in the following ways:
*
- * - A specific tool: `{ 'name': 'tool-name' }` or `'tool-name'`
- * - All tools in a group: `{ 'group': 'group-name' }`
+ * - A specific tool: `{ name: 'tool-name' }` or `'tool-name'`
+ * - All tools in a group: `{ group: 'group-name' }`
* - All tools: `'*'` - Using this will make the group a list with a "More" label by default
*
* @param {Object.<string,Array>} groups List of tool group configurations
// Check type has been registered
type = this.getToolGroupFactory().lookup( group.type ) ? group.type : defaultType;
items.push(
- this.getToolGroupFactory().create( type, this, $.extend( { '$': this.$ }, group ) )
+ this.getToolGroupFactory().create( type, this, $.extend( { $: this.$ }, group ) )
);
}
this.addItems( items );
*
* Tools can be specified in the following ways:
*
- * - A specific tool: `{ 'name': 'tool-name' }` or `'tool-name'`
- * - All tools in a group: `{ 'group': 'group-name' }`
+ * - A specific tool: `{ name: 'tool-name' }` or `'tool-name'`
+ * - All tools in a group: `{ group: 'group-name' }`
* - All tools: `'*'`
*
* @abstract
this.$element.on( {
'mousedown touchstart': OO.ui.bind( this.onPointerDown, this ),
'mouseup touchend': OO.ui.bind( this.onPointerUp, this ),
- 'mouseover': OO.ui.bind( this.onMouseOver, this ),
- 'mouseout': OO.ui.bind( this.onMouseOut, this )
+ mouseover: OO.ui.bind( this.onMouseOver, this ),
+ mouseout: OO.ui.bind( this.onMouseOut, this )
} );
- this.toolbar.getToolFactory().connect( this, { 'register': 'onToolFactoryRegister' } );
- this.aggregate( { 'disable': 'itemDisable' } );
- this.connect( this, { 'itemDisable': 'updateDisabled' } );
+ this.toolbar.getToolFactory().connect( this, { register: 'onToolFactoryRegister' } );
+ this.aggregate( { disable: 'itemDisable' } );
+ this.connect( this, { itemDisable: 'updateDisabled' } );
// Initialization
this.$group.addClass( 'oo-ui-toolGroup-tools' );
OO.ui.MessageDialog.static.message = null;
OO.ui.MessageDialog.static.actions = [
- { 'action': 'accept', 'label': OO.ui.deferMsg( 'ooui-dialog-message-accept' ), 'flags': 'primary' },
- { 'action': 'reject', 'label': OO.ui.deferMsg( 'ooui-dialog-message-reject' ), 'flags': 'safe' }
+ { action: 'accept', label: OO.ui.deferMsg( 'ooui-dialog-message-accept' ), flags: 'primary' },
+ { action: 'reject', label: OO.ui.deferMsg( 'ooui-dialog-message-reject' ), flags: 'safe' }
];
/* Methods */
OO.ui.MessageDialog.prototype.getActionProcess = function ( action ) {
if ( action ) {
return new OO.ui.Process( function () {
- this.close( { 'action': action } );
+ this.close( { action: action } );
}, this );
}
return OO.ui.MessageDialog.super.prototype.getActionProcess.call( this, action );
// Properties
this.$actions = this.$( '<div>' );
this.container = new OO.ui.PanelLayout( {
- '$': this.$, 'scrollable': true, 'classes': [ 'oo-ui-messageDialog-container' ]
+ $: this.$, scrollable: true, classes: [ 'oo-ui-messageDialog-container' ]
} );
this.text = new OO.ui.PanelLayout( {
- '$': this.$, 'padded': true, 'expanded': false, 'classes': [ 'oo-ui-messageDialog-text' ]
+ $: this.$, padded: true, expanded: false, classes: [ 'oo-ui-messageDialog-text' ]
} );
this.message = new OO.ui.LabelWidget( {
- '$': this.$, 'classes': [ 'oo-ui-messageDialog-message' ]
+ $: this.$, classes: [ 'oo-ui-messageDialog-message' ]
} );
// Initialization
this.$primaryActions = this.$( '<div>' );
this.$otherActions = this.$( '<div>' );
this.dismissButton = new OO.ui.ButtonWidget( {
- '$': this.$,
- 'label': OO.ui.msg( 'ooui-dialog-process-dismiss' )
+ $: this.$,
+ label: OO.ui.msg( 'ooui-dialog-process-dismiss' )
} );
this.retryButton = new OO.ui.ButtonWidget( {
- '$': this.$,
- 'label': OO.ui.msg( 'ooui-dialog-process-retry' )
+ $: this.$,
+ label: OO.ui.msg( 'ooui-dialog-process-retry' )
} );
this.$errors = this.$( '<div>' );
this.$errorsTitle = this.$( '<div>' );
// Events
- this.dismissButton.connect( this, { 'click': 'onDismissErrorButtonClick' } );
- this.retryButton.connect( this, { 'click': 'onRetryButtonClick' } );
+ this.dismissButton.connect( this, { click: 'onDismissErrorButtonClick' } );
+ this.retryButton.connect( this, { click: 'onRetryButtonClick' } );
// Initialization
this.title.$element.addClass( 'oo-ui-processDialog-title' );
this.$safeActions.is( ':visible' ) ? this.$safeActions.width() : 0,
this.$primaryActions.is( ':visible' ) ? this.$primaryActions.width() : 0
);
- this.$location.css( { 'padding-left': width, 'padding-right': width } );
+ this.$location.css( { paddingLeft: width, paddingRight: width } );
return this;
};
this.currentPageName = null;
this.pages = {};
this.ignoreFocus = false;
- this.stackLayout = new OO.ui.StackLayout( { '$': this.$, 'continuous': !!config.continuous } );
+ this.stackLayout = new OO.ui.StackLayout( { $: this.$, continuous: !!config.continuous } );
this.autoFocus = config.autoFocus === undefined || !!config.autoFocus;
this.outlineVisible = false;
this.outlined = !!config.outlined;
if ( this.outlined ) {
this.editable = !!config.editable;
this.outlineControlsWidget = null;
- this.outlineWidget = new OO.ui.OutlineWidget( { '$': this.$ } );
- this.outlinePanel = new OO.ui.PanelLayout( { '$': this.$, 'scrollable': true } );
+ this.outlineWidget = new OO.ui.OutlineWidget( { $: this.$ } );
+ this.outlinePanel = new OO.ui.PanelLayout( { $: this.$, scrollable: true } );
this.gridLayout = new OO.ui.GridLayout(
[ this.outlinePanel, this.stackLayout ],
- { '$': this.$, 'widths': [ 1, 2 ] }
+ { $: this.$, widths: [ 1, 2 ] }
);
this.outlineVisible = true;
if ( this.editable ) {
this.outlineControlsWidget = new OO.ui.OutlineControlsWidget(
- this.outlineWidget, { '$': this.$ }
+ this.outlineWidget, { $: this.$ }
);
}
}
// Events
- this.stackLayout.connect( this, { 'set': 'onStackLayoutSet' } );
+ this.stackLayout.connect( this, { set: 'onStackLayoutSet' } );
if ( this.outlined ) {
- this.outlineWidget.connect( this, { 'select': 'onOutlineWidgetSelect' } );
+ this.outlineWidget.connect( this, { select: 'onOutlineWidgetSelect' } );
}
if ( this.autoFocus ) {
// Event 'focus' does not bubble, but 'focusin' does
OO.ui.BookletLayout.prototype.onStackLayoutSet = function ( page ) {
var $input, layout = this;
if ( page ) {
- page.scrollElementIntoView( { 'complete': function () {
+ page.scrollElementIntoView( { complete: function () {
if ( layout.autoFocus ) {
// Set focus to the first input if nothing on the page is focused yet
if ( !page.$element.find( ':focus' ).length ) {
name = page.getName();
this.pages[page.getName()] = page;
if ( this.outlined ) {
- item = new OO.ui.OutlineItemWidget( name, page, { '$': this.$ } );
+ item = new OO.ui.OutlineItemWidget( name, page, { $: this.$ } );
page.setOutlineItem( item );
items.push( item );
}
* @mixins OO.ui.LabeledElement
*
* Available label alignment modes include:
- * - 'left': Label is before the field and aligned away from it, best for when the user will be
+ * - left: Label is before the field and aligned away from it, best for when the user will be
* scanning for a specific label in a form with many fields
- * - 'right': Label is before the field and aligned toward it, best for forms the user is very
+ * - right: Label is before the field and aligned toward it, best for forms the user is very
* familiar with and will tab through field checking quickly to verify which field they are in
- * - 'top': Label is before the field and above it, best for when the use will need to fill out all
+ * - top: Label is before the field and above it, best for when the use will need to fill out all
* fields from top to bottom in a form with few fields
- * - 'inline': Label is after the field and aligned toward it, best for small boolean fields like
+ * - inline: Label is after the field and aligned toward it, best for small boolean fields like
* checkboxes or radio buttons
*
* @constructor
OO.ui.FieldLayout = function OoUiFieldLayout( field, config ) {
var popupButtonWidget;
// Config initialization
- config = $.extend( { 'align': 'left' }, config );
+ config = $.extend( { align: 'left' }, config );
// Parent constructor
OO.ui.FieldLayout.super.call( this, config );
if ( config.help ) {
popupButtonWidget = new OO.ui.PopupButtonWidget( $.extend(
{
- '$': this.$,
- 'frameless': true,
- 'icon': 'info',
- 'title': config.help
+ $: this.$,
+ frameless: true,
+ icon: 'info',
+ title: config.help
},
config,
{ label: null }
if ( this.field instanceof OO.ui.InputWidget ) {
this.$label.on( 'click', OO.ui.bind( this.onLabelClick, this ) );
}
- this.field.connect( this, { 'disable': 'onFieldDisable' } );
+ this.field.connect( this, { disable: 'onFieldDisable' } );
// Initialization
this.$element.addClass( 'oo-ui-fieldLayout' );
panel = this.panels[i];
width = this.widths[x];
dimensions = {
- 'width': Math.round( width * 100 ) + '%',
- 'height': Math.round( height * 100 ) + '%',
- 'top': Math.round( top * 100 ) + '%',
+ width: Math.round( width * 100 ) + '%',
+ height: Math.round( height * 100 ) + '%',
+ top: Math.round( top * 100 ) + '%',
// HACK: Work around IE bug by setting visibility: hidden; if width or height is zero
- 'visibility': width === 0 || height === 0 ? 'hidden' : ''
+ visibility: width === 0 || height === 0 ? 'hidden' : ''
};
// If RTL, reverse:
if ( OO.ui.Element.getDir( this.$.context ) === 'rtl' ) {
*/
OO.ui.PageLayout = function OoUiPageLayout( name, config ) {
// Configuration initialization
- config = $.extend( { 'scrollable': true }, config );
+ config = $.extend( { scrollable: true }, config );
// Parent constructor
OO.ui.PageLayout.super.call( this, config );
*/
OO.ui.StackLayout = function OoUiStackLayout( config ) {
// Config initialization
- config = $.extend( { 'scrollable': true }, config );
+ config = $.extend( { scrollable: true }, config );
// Parent constructor
OO.ui.StackLayout.super.call( this, config );
// Mixin method
OO.ui.GroupElement.prototype.removeItems.call( this, items );
- if ( $.inArray( this.currentItem, items ) !== -1 ) {
+ if ( $.inArray( this.currentItem, items ) !== -1 ) {
if ( this.items.length ) {
this.setItem( this.items[0] );
} else {
OO.ui.MenuToolGroup.super.call( this, toolbar, config );
// Events
- this.toolbar.connect( this, { 'updateState': 'onUpdateState' } );
+ this.toolbar.connect( this, { updateState: 'onUpdateState' } );
// Initialization
this.$element.addClass( 'oo-ui-menuToolGroup' );
this.lookupInput = input;
this.$overlay = config.$overlay || this.$( 'body,.oo-ui-window-overlay' ).last();
this.lookupMenu = new OO.ui.TextInputMenuWidget( this, {
- '$': OO.ui.Element.getJQuery( this.$overlay ),
- 'input': this.lookupInput,
- '$container': config.$container
+ $: OO.ui.Element.getJQuery( this.$overlay ),
+ input: this.lookupInput,
+ $container: config.$container
} );
this.lookupCache = {};
this.lookupQuery = null;
this.$overlay.append( this.lookupMenu.$element );
this.lookupInput.$input.on( {
- 'focus': OO.ui.bind( this.onLookupInputFocus, this ),
- 'blur': OO.ui.bind( this.onLookupInputBlur, this ),
- 'mousedown': OO.ui.bind( this.onLookupInputMouseDown, this )
+ focus: OO.ui.bind( this.onLookupInputFocus, this ),
+ blur: OO.ui.bind( this.onLookupInputBlur, this ),
+ mousedown: OO.ui.bind( this.onLookupInputMouseDown, this )
} );
- this.lookupInput.connect( this, { 'change': 'onLookupInputChange' } );
+ this.lookupInput.connect( this, { change: 'onLookupInputChange' } );
// Initialization
this.$element.addClass( 'oo-ui-lookupWidget' );
*/
OO.ui.OutlineControlsWidget = function OoUiOutlineControlsWidget( outline, config ) {
// Configuration initialization
- config = $.extend( { 'icon': 'add-item' }, config );
+ config = $.extend( { icon: 'add-item' }, config );
// Parent constructor
OO.ui.OutlineControlsWidget.super.call( this, config );
this.outline = outline;
this.$movers = this.$( '<div>' );
this.upButton = new OO.ui.ButtonWidget( {
- '$': this.$,
- 'framed': false,
- 'icon': 'collapse',
- 'title': OO.ui.msg( 'ooui-outline-control-move-up' )
+ $: this.$,
+ framed: false,
+ icon: 'collapse',
+ title: OO.ui.msg( 'ooui-outline-control-move-up' )
} );
this.downButton = new OO.ui.ButtonWidget( {
- '$': this.$,
- 'framed': false,
- 'icon': 'expand',
- 'title': OO.ui.msg( 'ooui-outline-control-move-down' )
+ $: this.$,
+ framed: false,
+ icon: 'expand',
+ title: OO.ui.msg( 'ooui-outline-control-move-down' )
} );
this.removeButton = new OO.ui.ButtonWidget( {
- '$': this.$,
- 'framed': false,
- 'icon': 'remove',
- 'title': OO.ui.msg( 'ooui-outline-control-remove' )
+ $: this.$,
+ framed: false,
+ icon: 'remove',
+ title: OO.ui.msg( 'ooui-outline-control-remove' )
} );
// Events
outline.connect( this, {
- 'select': 'onOutlineChange',
- 'add': 'onOutlineChange',
- 'remove': 'onOutlineChange'
+ select: 'onOutlineChange',
+ add: 'onOutlineChange',
+ remove: 'onOutlineChange'
} );
- this.upButton.connect( this, { 'click': [ 'emit', 'move', -1 ] } );
- this.downButton.connect( this, { 'click': [ 'emit', 'move', 1 ] } );
- this.removeButton.connect( this, { 'click': [ 'emit', 'remove' ] } );
+ this.upButton.connect( this, { click: [ 'emit', 'move', -1 ] } );
+ this.downButton.connect( this, { click: [ 'emit', 'move', 1 ] } );
+ this.removeButton.connect( this, { click: [ 'emit', 'remove' ] } );
// Initialization
this.$element.addClass( 'oo-ui-outlineControlsWidget' );
*/
OO.ui.ButtonWidget = function OoUiButtonWidget( config ) {
// Configuration initialization
- config = $.extend( { 'target': '_blank' }, config );
+ config = $.extend( { target: '_blank' }, config );
// Parent constructor
OO.ui.ButtonWidget.super.call( this, config );
// Events
this.$button.on( {
- 'click': OO.ui.bind( this.onClick, this ),
- 'keypress': OO.ui.bind( this.onKeyPress, this )
+ click: OO.ui.bind( this.onClick, this ),
+ keypress: OO.ui.bind( this.onKeyPress, this )
} );
// Initialization
*/
OO.ui.ActionWidget = function OoUiActionWidget( config ) {
// Config intialization
- config = $.extend( { 'framed': false }, config );
+ config = $.extend( { framed: false }, config );
// Parent constructor
OO.ui.ActionWidget.super.call( this, config );
*/
OO.ui.InlineMenuWidget = function OoUiInlineMenuWidget( config ) {
// Configuration initialization
- config = $.extend( { 'indicator': 'down' }, config );
+ config = $.extend( { indicator: 'down' }, config );
// Parent constructor
OO.ui.InlineMenuWidget.super.call( this, config );
OO.ui.TitledElement.call( this, this.$label, config );
// Properties
- this.menu = new OO.ui.MenuWidget( $.extend( { '$': this.$, 'widget': this }, config.menu ) );
+ this.menu = new OO.ui.MenuWidget( $.extend( { $: this.$, widget: this }, config.menu ) );
this.$handle = this.$( '<span>' );
// Events
- this.$element.on( { 'click': OO.ui.bind( this.onClick, this ) } );
- this.menu.connect( this, { 'select': 'onMenuSelect' } );
+ this.$element.on( { click: OO.ui.bind( this.onClick, this ) } );
+ this.menu.connect( this, { select: 'onMenuSelect' } );
// Initialization
this.$handle
*/
OO.ui.InputWidget = function OoUiInputWidget( config ) {
// Config intialization
- config = $.extend( { 'readOnly': false }, config );
+ config = $.extend( { readOnly: false }, config );
// Parent constructor
OO.ui.InputWidget.super.call( this, config );
*/
OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
var widget = this;
- config = $.extend( { 'maxRows': 10 }, config );
+ config = $.extend( { maxRows: 10 }, config );
// Parent constructor
OO.ui.TextInputWidget.super.call( this, config );
if ( this.multiline && this.autosize ) {
$clone = this.$input.clone()
.val( this.$input.val() )
- .css( { 'height': 0 } )
+ .css( { height: 0 } )
.insertAfter( this.$input );
// Set inline height property to 0 to measure scroll height
scrollHeight = $clone[0].scrollHeight;
*/
OO.ui.MenuItemWidget = function OoUiMenuItemWidget( data, config ) {
// Configuration initialization
- config = $.extend( { 'icon': 'check' }, config );
+ config = $.extend( { icon: 'check' }, config );
// Parent constructor
OO.ui.MenuItemWidget.super.call( this, data, config );
this.width = config.width !== undefined ? config.width : 320;
this.height = config.height !== undefined ? config.height : null;
this.align = config.align || 'center';
- this.closeButton = new OO.ui.ButtonWidget( { '$': this.$, 'framed': false, 'icon': 'close' } );
+ this.closeButton = new OO.ui.ButtonWidget( { $: this.$, framed: false, icon: 'close' } );
this.onMouseDownHandler = OO.ui.bind( this.onMouseDown, this );
// Events
- this.closeButton.connect( this, { 'click': 'onCloseButtonClick' } );
+ this.closeButton.connect( this, { click: 'onCloseButtonClick' } );
// Initialization
this.toggleAnchor( config.anchor === undefined || config.anchor );
containerLeft = Math.round( this.$container.offset().left ),
containerWidth = this.$container.innerWidth(),
containerRight = containerLeft + containerWidth,
- popupOffset = this.width * ( { 'left': 0, 'center': -0.5, 'right': -1 } )[this.align],
+ popupOffset = this.width * ( { left: 0, center: -0.5, right: -1 } )[this.align],
anchorWidth = this.$anchor.width(),
popupLeft = popupOffset - padding,
popupRight = popupOffset + padding + this.width + padding,
// Position body relative to anchor and resize
this.$popup.css( {
- 'left': popupOffset,
- 'width': this.width,
- 'height': this.height !== null ? this.height : 'auto'
+ left: popupOffset,
+ width: this.width,
+ height: this.height !== null ? this.height : 'auto'
} );
if ( transition ) {
// Properties
this.query = new OO.ui.TextInputWidget( {
- '$': this.$,
- 'icon': 'search',
- 'placeholder': config.placeholder,
- 'value': config.value
+ $: this.$,
+ icon: 'search',
+ placeholder: config.placeholder,
+ value: config.value
} );
- this.results = new OO.ui.SelectWidget( { '$': this.$ } );
+ this.results = new OO.ui.SelectWidget( { $: this.$ } );
this.$query = this.$( '<div>' );
this.$results = this.$( '<div>' );
// Events
this.query.connect( this, {
- 'change': 'onQueryChange',
- 'enter': 'onQueryEnter'
+ change: 'onQueryChange',
+ enter: 'onQueryEnter'
} );
this.results.connect( this, {
- 'highlight': 'onResultsHighlight',
- 'select': 'onResultsSelect'
+ highlight: 'onResultsHighlight',
+ select: 'onResultsSelect'
} );
this.query.$input.on( 'keydown', OO.ui.bind( this.onQueryKeydown, this ) );
// Events
this.$element.on( {
- 'mousedown': OO.ui.bind( this.onMouseDown, this ),
- 'mouseover': OO.ui.bind( this.onMouseOver, this ),
- 'mouseleave': OO.ui.bind( this.onMouseLeave, this )
+ mousedown: OO.ui.bind( this.onMouseDown, this ),
+ mouseover: OO.ui.bind( this.onMouseOver, this ),
+ mouseleave: OO.ui.bind( this.onMouseLeave, this )
} );
// Initialization
/*!
- * OOjs UI v0.1.0-pre (a7ce4d48d9)
+ * OOjs UI v0.1.0-pre (e9cf571db2)
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2014 OOjs Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2014-07-23T23:48:16Z
+ * Date: 2014-07-28T21:48:00Z
*/
/* Textures */
+++ /dev/null
-/*!
- * jQuery UI Accordion 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Accordion#theming
- */
-.ui-accordion .ui-accordion-header { display: block; cursor: pointer; position: relative; margin-top: 2px; padding: .5em .5em .5em .7em; zoom: 1; }
-.ui-accordion .ui-accordion-icons { padding-left: 2.2em; }
-.ui-accordion .ui-accordion-noicons { padding-left: .7em; }
-.ui-accordion .ui-accordion-icons .ui-accordion-icons { padding-left: 2.2em; }
-.ui-accordion .ui-accordion-header .ui-accordion-header-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
-.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; overflow: auto; zoom: 1; }
+++ /dev/null
-/*!
- * jQuery UI Autocomplete 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Autocomplete#theming
- */
-.ui-autocomplete {
- position: absolute;
- top: 0;
- left: 0;
- cursor: default;
-}
-.ui-autocomplete-loading { /* @embed */ background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; }
-
-/* workarounds */
-* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+++ /dev/null
-/*!
- * jQuery UI Button 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Button#theming
- */
-.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
-.ui-button, .ui-button:link, .ui-button:visited, .ui-button:hover, .ui-button:active { text-decoration: none; }
-.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
-button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
-.ui-button-icons-only { width: 3.4em; }
-button.ui-button-icons-only { width: 3.7em; }
-
-/*button text element */
-.ui-button .ui-button-text { display: block; line-height: 1.4; }
-.ui-button-text-only .ui-button-text { padding: .125em .25em; }
-.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
-.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
-.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
-.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
-/* no icon support for input elements, provide padding by default */
-input.ui-button { padding: .4em 1em; }
-
-/*button icon element(s) */
-.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
-.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
-.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
-.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
-.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
-
-/*button sets*/
-.ui-buttonset { margin-right: 7px; }
-.ui-buttonset .ui-button { margin-left: 0; margin-right: -.4em; }
-
-/* workarounds */
-button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
-
-/* Disables the annoying dashed border Firefox puts on active buttons */
-body button.ui-button::-moz-focus-inner {
- border: 0;
-}
-/* Give large buttons some extra padding */
-body .ui-button-large {
- padding: 5px;
-}
-/* Use white icons for colored buttons */
-.ui-button-green .ui-icon,
-.ui-button-blue .ui-icon,
-.ui-button-red .ui-icon,
-.ui-button-orange .ui-icon {
- /* @embed */
- background-image: url(images/ui-icons_ffffff_256x240.png) !important;
-}
-
-/* Corner radius */
-/* This is normally handled in jquery.ui.theme.css, but in our case, the corner
- styling of our buttons doesn't match our default widget corner styling */
-.ui-button.ui-corner-all,
-.ui-button.ui-corner-top,
-.ui-button.ui-corner-left,
-.ui-button.ui-corner-tl {
- border-top-left-radius: 4px;
-}
-.ui-button.ui-corner-all,
-.ui-button.ui-corner-top,
-
-.ui-button.ui-corner-right,
-.ui-button.ui-corner-tr {
- border-top-right-radius: 4px;
-}
-.ui-button.ui-corner-all,
-.ui-button.ui-corner-bottom,
-.ui-button.ui-corner-left,
-.ui-button.ui-corner-bl {
- border-bottom-left-radius: 4px;
-}
-.ui-button.ui-corner-all,
-.ui-button.ui-corner-bottom,
-.ui-button.ui-corner-right,
-.ui-button.ui-corner-br {
- border-bottom-right-radius: 4px;
-}
-
-body .ui-button {
- color: #2779aa;
- margin: 0.5em 0 0.5em 0.4em;
- border: 1px solid #aaa !important;
- background: #f0f0f0 !important;
- background: -moz-linear-gradient(top, #fff 0%, #ddd 90%) !important; /* FF3.6+ */
- background: -webkit-linear-gradient(top, #fff 0%, #ddd 90%) !important; /* Chrome10+, Safari5.1+ */
- background: -o-linear-gradient(top, #fff 0%, #ddd 90%) !important; /* Opera 11.10+ */
- background: -ms-linear-gradient(top, #fff 0%, #ddd 90%) !important; /* IE10+ */
- background: linear-gradient(to bottom, #fff 0%, #ddd 90%) !important;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dddddd', GradientType=0); /* IE6-8 */
- cursor: pointer;
- font-size: 1em;
- line-height: 1.4em;
- width: auto;
- overflow: visible;
- box-shadow: 0 1px 3px rgba(0,0,0,.2);
-}
-
-body .ui-button-icon-only {
- width: 2.2em;
-}
-
-body .ui-button-icons-only {
- width: 3.4em;
-}
-
-body .ui-button:hover {
- color: #2779aa;
- border-color: #bbb !important;
- background: #fff !important;
- background: -moz-linear-gradient(top, #fff 0%, #eee 90%) !important; /* FF3.6+ */
- background: -webkit-linear-gradient(top, #fff 0%, #eee 90%) !important; /* Chrome10+, Safari5.1+ */
- background: -o-linear-gradient(top, #fff 0%, #eee 90%) !important; /* Opera 11.10+ */
- background: -ms-linear-gradient(top, #fff 0%, #eee 90%) !important; /* IE10+ */
- background: linear-gradient(to bottom, #fff 0%, #eee 90%) !important;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0); /* IE6-8 */
- box-shadow: 0 1px 3px rgba(0,0,0,.1);
-}
-body .ui-button:active,
-body .ui-button:focus {
- border-color: #8ad !important;
- box-shadow: 0 0 1px 1px rgba(167,215,249,.5);
-}
-body .ui-button:active {
- background: #e0e0e0 !important;
- background: -moz-linear-gradient(top, #f0f0f0 0%, #d0d0d0 90%) !important; /* FF3.6+ */
- background: -webkit-linear-gradient(top, #f0f0f0 0%, #d0d0d0 90%) !important; /* Chrome10+, Safari5.1+ */
- background: -o-linear-gradient(top, #f0f0f0 0%, #d0d0d0 90%) !important; /* Opera 11.10+ */
- background: -ms-linear-gradient(top, #f0f0f0 0%, #d0d0d0 90%) !important; /* IE10+ */
- background: linear-gradient(to bottom, #f0f0f0 0%, #d0d0d0 90%) !important;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f0f0f0', endColorstr='#d0d0d0', GradientType=0); /* IE6-8 */
-}
-
-/* Green buttons */
-body .ui-button-green,
-body .ui-button-green .ui-button-text {
- color: white;
- text-shadow: 0 -1px 1px #072;
-}
-body .ui-button.ui-button-green {
- border-color: #294 !important;
- background: #295 !important;
- background: -moz-linear-gradient(top, #3c8 0%, #295 90%) !important; /* FF3.6+ */
- background: -webkit-linear-gradient(top, #3c8 0%, #295 90%) !important; /* Chrome10+, Safari5.1+ */
- background: -o-linear-gradient(top, #3c8 0%, #295 90%) !important; /* Opera 11.10+ */
- background: -ms-linear-gradient(top, #3c8 0%, #295 90%) !important; /* IE10+ */
- background: linear-gradient(to bottom, #3c8 0%, #295 90%) !important;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#33cc88', endColorstr='#229955', GradientType=0); /* IE6-8 */
- box-shadow: 0 1px 3px rgba(0,0,0,.3);
-}
-body .ui-button.ui-button-green:hover {
- background: #33a055 !important;
- background: -moz-linear-gradient(top, #44d388 0%, #33a055 90%) !important; /* FF3.6+ */
- background: -webkit-linear-gradient(top, #44d388 0%, #33a055 90%) !important; /* Chrome10+, Safari5.1+ */
- background: -o-linear-gradient(top, #44d388 0%, #33a055 90%) !important; /* Opera 11.10+ */
- background: -ms-linear-gradient(top, #44d388 0%, #33a055 90%) !important; /* IE10+ */
- background: linear-gradient(to bottom, #44d388 0%, #33a055 90%) !important;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#44d388', endColorstr='#33a055', GradientType=0); /* IE6-8 */
- box-shadow: 0 1px 3px rgba(0,0,0,.25);
-}
-body .ui-button.ui-button-green:active,
-body .ui-button.ui-button-green:focus {
- border-color: #172 !important;
- box-shadow: 0 0 2px 2px rgba(167,215,249,.75);
-}
-body .ui-button.ui-button-green:active {
- background: #338855 !important;
- background: -moz-linear-gradient(top, #30c080 0%, #338855 90%) !important; /* FF3.6+ */
- background: -webkit-linear-gradient(top, #30c080 0%, #338855 90%) !important; /* Chrome10+, Safari5.1+ */
- background: -o-linear-gradient(top, #30c080 0%, #338855 90%) !important; /* Opera 11.10+ */
- background: -ms-linear-gradient(top, #30c080 0%, #338855 90%) !important; /* IE10+ */
- background: linear-gradient(to bottom, #30c080 0%, #338855 90%) !important;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#30c080', endColorstr='#338855', GradientType=0); /* IE6-8 */
-}
-
-/* Blue buttons */
-body .ui-button-blue,
-body .ui-button-blue .ui-button-text {
- color: white;
- text-shadow: 0 -1px 1px #037;
-}
-body .ui-button.ui-button-blue {
- border-color: #468 !important;
- background: #36b !important;
- background: -moz-linear-gradient(top, #48e 0%, #36b 90%) !important; /* FF3.6+ */
- background: -webkit-linear-gradient(top, #48e 0%, #36b 90%) !important; /* Chrome10+, Safari5.1+ */
- background: -o-linear-gradient(top, #48e 0%, #36b 90%) !important; /* Opera 11.10+ */
- background: -ms-linear-gradient(top, #48e 0%, #36b 90%) !important; /* IE10+ */
- background: linear-gradient(to bottom, #48e 0%, #36b 90%) !important;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#4488ee', endColorstr='#3366bb', GradientType=0); /* IE6-8 */
- box-shadow: 0 1px 3px rgba(0,0,0,.35);
-}
-body .ui-button.ui-button-blue:hover {
- background: #36c !important;
- background: -moz-linear-gradient(top, #59e 0%, #36c 90%) !important; /* FF3.6+ */
- background: -webkit-linear-gradient(top, #59e 0%, #36c 90%) !important; /* Chrome10+, Safari5.1+ */
- background: -o-linear-gradient(top, #59e 0%, #36c 90%) !important; /* Opera 11.10+ */
- background: -ms-linear-gradient(top, #59e 0%, #36c 90%) !important; /* IE10+ */
- background: linear-gradient(to bottom, #59e 0%, #36c 90%) !important;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5599ee', endColorstr='#3366cc', GradientType=0); /* IE6-8 */
-}
-body .ui-button.ui-button-blue:active,
-body .ui-button.ui-button-blue:focus {
- border-color: #357 !important;
- box-shadow: 0 0 2px 2px rgba(167,215,249,.75);
-}
-body .ui-button.ui-button-blue:active {
- background: #3060a0 !important;
- background: -moz-linear-gradient(top, #4080e0 0%, #3060a0 90%) !important; /* FF3.6+ */
- background: -webkit-linear-gradient(top, #4080e0 0%, #3060a0 90%) !important; /* Chrome10+, Safari5.1+ */
- background: -o-linear-gradient(top, #4080e0 0%, #3060a0 90%) !important; /* Opera 11.10+ */
- background: -ms-linear-gradient(top, #4080e0 0%, #3060a0 90%) !important; /* IE10+ */
- background: linear-gradient(to bottom, #4080e0 0%, #3060a0 90%) !important;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#4080e0', endColorstr='#3060a0', GradientType=0); /* IE6-8 */
-}
-
-/* Red buttons */
-body .ui-button-red,
-body .ui-button-red .ui-button-text {
- color: white;
- text-shadow: 0 -1px 1px #700;
-}
-body .ui-button.ui-button-red {
- border-color: #944 !important;
- background: #a22 !important;
- background: -moz-linear-gradient(top, #d44 0%, #a22 90%) !important; /* FF3.6+ */
- background: -webkit-linear-gradient(top, #d44 0%, #a22 90%) !important; /* Chrome10+, Safari5.1+ */
- background: -o-linear-gradient(top, #d44 0%, #a22 90%) !important; /* Opera 11.10+ */
- background: -ms-linear-gradient(top, #d44 0%, #a22 90%) !important; /* IE10+ */
- background: linear-gradient(to bottom, #d44 0%, #a22 90%) !important;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#dd4444', endColorstr='#aa2222', GradientType=0); /* IE6-8 */
- box-shadow: 0 1px 3px rgba(0,0,0,.35);
-}
-body .ui-button.ui-button-red:hover {
- border-color: #a44 !important;
- background: #b03333 !important;
- background: -moz-linear-gradient(top, #ee4646 0%, #b03333 90%) !important; /* FF3.6+ */
- background: -webkit-linear-gradient(top, #ee4646 0%, #b03333 90%) !important; /* Chrome10+, Safari5.1+ */
- background: -o-linear-gradient(top, #ee4646 0%, #b03333 90%) !important; /* Opera 11.10+ */
- background: -ms-linear-gradient(top, #ee4646 0%, #b03333 90%) !important; /* IE10+ */
- background: linear-gradient(to bottom, #ee4646 0%, #b03333 90%) !important;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee4646', endColorstr='#b03333', GradientType=0); /* IE6-8 */
- box-shadow: 0 1px 3px rgba(0,0,0,.3);
-}
-body .ui-button.ui-button-red:active,
-body .ui-button.ui-button-red:focus {
- border-color: #747 !important;
- box-shadow: 0 0 2px 2px rgba(167,215,249,.7);
-}
-body .ui-button.ui-button-red:active {
- background: #952020 !important;
- background: -moz-linear-gradient(top, #d04545 0%, #952020 90%) !important; /* FF3.6+ */
- background: -webkit-linear-gradient(top, #d04545 0%, #952020 90%) !important; /* Chrome10+, Safari5.1+ */
- background: -o-linear-gradient(top, #d04545 0%, #952020 90%) !important; /* Opera 11.10+ */
- background: -ms-linear-gradient(top, #d04545 0%, #952020 90%) !important; /* IE10+ */
- background: linear-gradient(to bottom, #d04545 0%, #952020 90%) !important;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#d04545', endColorstr='#952020', GradientType=0); /* IE6-8 */
-}
-
-/* Disabled buttons */
-body .ui-button-green.disabled,
-body .ui-button-green.disabled:hover,
-body .ui-button-green.disabled:active,
-body .ui-button-green.disabled:focus,
-body .ui-button-blue.disabled,
-body .ui-button-blue.disabled:hover,
-body .ui-button-blue.disabled:active,
-body .ui-button-blue.disabled:focus,
-body .ui-button-red.disabled,
-body .ui-button-red.disabled:hover,
-body .ui-button-red.disabled:active,
-body .ui-button-red.disabled:focus,
-body .ui-button.disabled,
-body .ui-button.disabled:hover {
- color: #aaa;
- border-color: #ccc !important;
- background: #eee !important;
- background: -moz-linear-gradient(top, #f6f6f6 0%, #eee 90%) !important; /* FF3.6+ */
- background: -webkit-linear-gradient(top, #f6f6f6 0%, #eee 90%) !important; /* Chrome10+, Safari5.1+ */
- background: -o-linear-gradient(top, #f6f6f6 0%, #eee 90%) !important; /* Opera 11.10+ */
- background: -ms-linear-gradient(top, #f6f6f6 0%, #eee 90%) !important; /* IE10+ */
- background: linear-gradient(to bottom, #f6f6f6 0%, #eee 90%) !important;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f6f6f6', endColorstr='#eeeeee', GradientType=0); /* IE6-8 */
- box-shadow: 0 1px 3px rgba(0,0,0,0);
-}
-body .ui-button-green.disabled .ui-button-text,
-body .ui-button-blue.disabled .ui-button-text,
-body .ui-button-red.disabled .ui-button-text {
- color: #aaa;
- text-shadow: 0 1px 1px #fff;
-}
+++ /dev/null
-/*!
- * jQuery UI CSS Framework 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- */
-
-/* Layout helpers
-----------------------------------*/
-.ui-helper-hidden { display: none; }
-.ui-helper-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
-.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
-.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
-.ui-helper-clearfix:after { clear: both; }
-.ui-helper-clearfix { zoom: 1; }
-.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
-
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-disabled { cursor: default !important; }
-
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Overlays */
-.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+++ /dev/null
-/*!
- * jQuery UI Datepicker 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Datepicker#theming
- */
-.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
-.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
-.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
-.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
-.ui-datepicker .ui-datepicker-prev { left:2px; }
-.ui-datepicker .ui-datepicker-next { right:2px; }
-.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
-.ui-datepicker .ui-datepicker-next-hover { right:1px; }
-.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
-.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
-.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; padding:1px 0; }
-.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
-.ui-datepicker select.ui-datepicker-month,
-.ui-datepicker select.ui-datepicker-year { width: 49%;}
-.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
-.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
-.ui-datepicker td { border: 0; padding: 1px; }
-.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
-.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-top: 1px solid #DDDDDD; border-left: 0; border-right: 0; border-bottom: 0; }
-.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
-.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
-
-/* with multiple calendars */
-.ui-datepicker.ui-datepicker-multi { width:auto; }
-.ui-datepicker-multi .ui-datepicker-group { float:left; }
-.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
-.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
-.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
-.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
-.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
-.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
-
-/* RTL support */
-/* @noflip */ .ui-datepicker-rtl { direction: rtl; }
-/* @noflip */ .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
-/* @noflip */ .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
-/* @noflip */ .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
-/* @noflip */ .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
-/* @noflip */ .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
-/* @noflip */ .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
-/* @noflip */ .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
-/* @noflip */ .ui-datepicker-rtl .ui-datepicker-group { float:right; }
-/* @noflip */ .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-/* @noflip */ .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-
-/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
-.ui-datepicker-cover {
- position: absolute; /*must have*/
- z-index: -1; /*must have*/
- filter: mask(); /*must have*/
- top: -4px; /*must have*/
- left: -4px; /*must have*/
- width: 200px; /*must have*/
- height: 200px; /*must have*/
-}
\ No newline at end of file
+++ /dev/null
-/*!
- * jQuery UI Dialog 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Dialog#theming
- */
-.ui-dialog { position: absolute; top: 0; left: 0; padding: 0; width: 300px; }
-.ui-dialog .ui-dialog-titlebar { padding: .75em; position: relative; }
-.ui-dialog .ui-dialog-title { float: left; margin: 0; }
-.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .75em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
-.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
-.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
-.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
-.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
-.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
-.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
-.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
-.ui-draggable .ui-dialog-titlebar { cursor: move; }
-
-/* Customizations */
-body .ui-dialog .ui-dialog-titlebar-close:hover {
- text-decoration: none;
-}
-body .ui-dialog .ui-dialog-content .status-invalid input {
- border: 2px solid red;
- padding: 2px 1px;
-}
-body .ui-dialog .ui-dialog-titlebar {
- padding: 0.9em 1.4em 0.6em !important;
-}
-body .ui-dialog .ui-widget-header {
- /* @embed */
- background: #f0f0f0 url(images/titlebar-fade.png) repeat-x scroll 50% 100% !important;
-}
-/* FIXME: Should just update the icon sprite if we're keeping this X */
-body .ui-dialog .ui-icon-closethick {
- /* @embed */
- background: url(images/close.png) no-repeat 50% 50% !important;
-}
-body .ui-dialog .ui-dialog-buttonpane {
- margin-top: 0 !important;
- padding:0.3em 1.4em 0.5em 1.4em !important;
-}
+++ /dev/null
-/*!
- * jQuery UI Progressbar 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Progressbar#theming
- */
-.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
-.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file
+++ /dev/null
-/*!
- * jQuery UI Resizable 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Resizable#theming
- */
-.ui-resizable { position: relative;}
-.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; }
-.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
-.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
-.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
-/* @noflip */
-.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
-/* @noflip */
-.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
-/* @noflip */
-.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
-/* @noflip */
-.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
-/* @noflip */
-.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
-/* @noflip */
-.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
\ No newline at end of file
+++ /dev/null
-/*!
- * jQuery UI Selectable 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Selectable#theming
- */
-.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
+++ /dev/null
-/*!
- * jQuery UI Slider 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Slider#theming
- */
-.ui-slider { position: relative; text-align: left; }
-.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
-.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
-
-.ui-slider-horizontal { height: .8em; }
-.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
-.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
-.ui-slider-horizontal .ui-slider-range-min { left: 0; }
-.ui-slider-horizontal .ui-slider-range-max { right: 0; }
-
-.ui-slider-vertical { width: .8em; height: 100px; }
-.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
-.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
-.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
-.ui-slider-vertical .ui-slider-range-max { top: 0; }
\ No newline at end of file
+++ /dev/null
-/*!
- * jQuery UI Tabs 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Tabs#theming
- */
-.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
-.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
-.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 0; margin: 1px .2em 0 0; border-bottom: 0; padding: 0; white-space: nowrap; }
-.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-active { margin-bottom: -1px; padding-bottom: 1px; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-active a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-tabs-loading a { cursor: text; }
-.ui-tabs .ui-tabs-nav li a, .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
-.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
+++ /dev/null
-/*!
- * jQuery UI CSS Framework 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- *
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=sans-serif&fwDefault=normal&fsDefault=1.0em&cornerRadius=3px&bgColorHeader=ffffff&bgTextureHeader=highlight_soft&bgImgOpacityHeader=100&borderColorHeader=aed0ea&fcHeader=222222&iconColorHeader=72a7cf&bgColorContent=f2f5f7&bgTextureContent=highlight_hard&bgImgOpacityContent=100&borderColorContent=cccccc&fcContent=362b36&iconColorContent=72a7cf&bgColorDefault=d7ebf9&bgTextureDefault=highlight_hard&bgImgOpacityDefault=80&borderColorDefault=aed0ea&fcDefault=2779aa&iconColorDefault=3d80b3&bgColorHover=e4f1fb&bgTextureHover=highlight_soft&bgImgOpacityHover=100&borderColorHover=74b2e2&fcHover=0070a3&iconColorHover=2694e8&bgColorActive=f0f0f0&bgTextureActive=inset_hard&bgImgOpacityActive=100&borderColorActive=cccccc&fcActive=000000&iconColorActive=666666&bgColorHighlight=ffef8f&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=25&borderColorHighlight=f9dd34&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=cd0a0a&bgTextureError=flat&bgImgOpacityError=15&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffffff&bgColorOverlay=000000&bgTextureOverlay=glow_ball&bgImgOpacityOverlay=100&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=70&opacityShadow=20&thicknessShadow=7px&offsetTopShadow=-7px&offsetLeftShadow=-7px&cornerRadiusShadow=8px
- */
-
-
-/* Component containers
-----------------------------------*/
-.ui-widget { font-family: sans-serif; font-size: 0.8em; }
-.ui-widget .ui-widget { font-size: 1em; }
-.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: sans-serif; font-size: 1em; }
-.ui-widget-content { border: 1px solid #cccccc; /* @embed */ background: #f2f5f7 url("images/ui-bg_highlight-hard_100_f2f5f7_1x100.png") 50% top repeat-x; color: #362b36; }
-.ui-widget-header { border-bottom: 1px solid #bbbbbb; line-height: 1em; /* @embed */ background: #ffffff url("images/ui-bg_highlight-soft_100_ffffff_1x100.png") 50% 50% repeat-x; color: #222222; font-weight: bold; }
-
-/* Interaction states
-----------------------------------*/
-.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #aed0ea; /* @embed */ background: #d7ebf9 url("images/ui-bg_highlight-hard_80_d7ebf9_1x100.png") 50% 50% repeat-x; font-weight: normal; color: #2779aa; }
-.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2779aa; text-decoration: none; }
-.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #74b2e2; /* @embed */ background: #e4f1fb url("images/ui-bg_highlight-soft_100_e4f1fb_1x100.png") 50% 50% repeat-x; font-weight: normal; color: #0070a3; }
-.ui-state-hover a, .ui-state-hover a:hover, .ui-state-hover a:link, .ui-state-hover a:visited { color: #0070a3; text-decoration: none; }
-.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #cccccc; background: #f0f0f0 /* @embed */ url("images/ui-bg_inset-hard_100_f0f0f0_1x100.png") 50% 50% repeat-x; font-weight: normal; color: #000000; }
-.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #000000; text-decoration: none; }
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #f9dd34; background: #ffef8f /* @embed */ url("images/ui-bg_highlight-soft_25_ffef8f_1x100.png") 50% top repeat-x; color: #363636; }
-.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
-.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #cd0a0a /* @embed */ url("images/ui-bg_flat_15_cd0a0a_40x100.png") 50% 50% repeat-x; color: #ffffff; }
-.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
-.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
-.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
-.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
-.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
-.ui-state-disabled .ui-icon { filter:Alpha(Opacity=35); } /* For IE8 - See #6059 */
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { width: 16px; height: 16px; }
-.ui-icon, .ui-widget-content .ui-icon, .ui-widget-header .ui-icon { /* @embed */ background-image: url("images/ui-icons_72a7cf_256x240.png"); }
-.ui-state-default .ui-icon { /* @embed */ background-image: url("images/ui-icons_3d80b3_256x240.png"); }
-.ui-state-hover .ui-icon, .ui-state-focus .ui-icon { /* @embed */ background-image: url("images/ui-icons_2694e8_256x240.png"); }
-.ui-state-active .ui-icon { /* @embed */ background-image: url("images/ui-icons_666666_256x240.png"); }
-.ui-state-highlight .ui-icon { /* @embed */ background-image: url("images/ui-icons_2e83ff_256x240.png"); }
-.ui-state-error .ui-icon, .ui-state-error-text .ui-icon { /* @embed */ background-image: url("images/ui-icons_ffffff_256x240.png"); }
-
-/* positioning */
-.ui-icon-carat-1-n { background-position: 0 0; }
-.ui-icon-carat-1-ne { background-position: -16px 0; }
-.ui-icon-carat-1-e { background-position: -32px 0; }
-.ui-icon-carat-1-se { background-position: -48px 0; }
-.ui-icon-carat-1-s { background-position: -64px 0; }
-.ui-icon-carat-1-sw { background-position: -80px 0; }
-.ui-icon-carat-1-w { background-position: -96px 0; }
-.ui-icon-carat-1-nw { background-position: -112px 0; }
-.ui-icon-carat-2-n-s { background-position: -128px 0; }
-.ui-icon-carat-2-e-w { background-position: -144px 0; }
-.ui-icon-triangle-1-n { background-position: 0 -16px; }
-.ui-icon-triangle-1-ne { background-position: -16px -16px; }
-.ui-icon-triangle-1-e { background-position: -32px -16px; }
-.ui-icon-triangle-1-se { background-position: -48px -16px; }
-.ui-icon-triangle-1-s { background-position: -64px -16px; }
-.ui-icon-triangle-1-sw { background-position: -80px -16px; }
-.ui-icon-triangle-1-w { background-position: -96px -16px; }
-.ui-icon-triangle-1-nw { background-position: -112px -16px; }
-.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
-.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
-.ui-icon-arrow-1-n { background-position: 0 -32px; }
-.ui-icon-arrow-1-ne { background-position: -16px -32px; }
-.ui-icon-arrow-1-e { background-position: -32px -32px; }
-.ui-icon-arrow-1-se { background-position: -48px -32px; }
-.ui-icon-arrow-1-s { background-position: -64px -32px; }
-.ui-icon-arrow-1-sw { background-position: -80px -32px; }
-.ui-icon-arrow-1-w { background-position: -96px -32px; }
-.ui-icon-arrow-1-nw { background-position: -112px -32px; }
-.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
-.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
-.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
-.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
-.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
-.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
-.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
-.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
-.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
-.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
-.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
-.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
-.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
-.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
-.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
-.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
-.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
-.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
-.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
-.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
-.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
-.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
-.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
-.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
-.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
-.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
-.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
-.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
-.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
-.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
-.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
-.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
-.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
-.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
-.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
-.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
-.ui-icon-arrow-4 { background-position: 0 -80px; }
-.ui-icon-arrow-4-diag { background-position: -16px -80px; }
-.ui-icon-extlink { background-position: -32px -80px; }
-.ui-icon-newwin { background-position: -48px -80px; }
-.ui-icon-refresh { background-position: -64px -80px; }
-.ui-icon-shuffle { background-position: -80px -80px; }
-.ui-icon-transfer-e-w { background-position: -96px -80px; }
-.ui-icon-transferthick-e-w { background-position: -112px -80px; }
-.ui-icon-folder-collapsed { background-position: 0 -96px; }
-.ui-icon-folder-open { background-position: -16px -96px; }
-.ui-icon-document { background-position: -32px -96px; }
-.ui-icon-document-b { background-position: -48px -96px; }
-.ui-icon-note { background-position: -64px -96px; }
-.ui-icon-mail-closed { background-position: -80px -96px; }
-.ui-icon-mail-open { background-position: -96px -96px; }
-.ui-icon-suitcase { background-position: -112px -96px; }
-.ui-icon-comment { background-position: -128px -96px; }
-.ui-icon-person { background-position: -144px -96px; }
-.ui-icon-print { background-position: -160px -96px; }
-.ui-icon-trash { background-position: -176px -96px; }
-.ui-icon-locked { background-position: -192px -96px; }
-.ui-icon-unlocked { background-position: -208px -96px; }
-.ui-icon-bookmark { background-position: -224px -96px; }
-.ui-icon-tag { background-position: -240px -96px; }
-.ui-icon-home { background-position: 0 -112px; }
-.ui-icon-flag { background-position: -16px -112px; }
-.ui-icon-calendar { background-position: -32px -112px; }
-.ui-icon-cart { background-position: -48px -112px; }
-.ui-icon-pencil { background-position: -64px -112px; }
-.ui-icon-clock { background-position: -80px -112px; }
-.ui-icon-disk { background-position: -96px -112px; }
-.ui-icon-calculator { background-position: -112px -112px; }
-.ui-icon-zoomin { background-position: -128px -112px; }
-.ui-icon-zoomout { background-position: -144px -112px; }
-.ui-icon-search { background-position: -160px -112px; }
-.ui-icon-wrench { background-position: -176px -112px; }
-.ui-icon-gear { background-position: -192px -112px; }
-.ui-icon-heart { background-position: -208px -112px; }
-.ui-icon-star { background-position: -224px -112px; }
-.ui-icon-link { background-position: -240px -112px; }
-.ui-icon-cancel { background-position: 0 -128px; }
-.ui-icon-plus { background-position: -16px -128px; }
-.ui-icon-plusthick { background-position: -32px -128px; }
-.ui-icon-minus { background-position: -48px -128px; }
-.ui-icon-minusthick { background-position: -64px -128px; }
-.ui-icon-close { background-position: -80px -128px; }
-.ui-icon-closethick { background-position: -96px -128px; }
-.ui-icon-key { background-position: -112px -128px; }
-.ui-icon-lightbulb { background-position: -128px -128px; }
-.ui-icon-scissors { background-position: -144px -128px; }
-.ui-icon-clipboard { background-position: -160px -128px; }
-.ui-icon-copy { background-position: -176px -128px; }
-.ui-icon-contact { background-position: -192px -128px; }
-.ui-icon-image { background-position: -208px -128px; }
-.ui-icon-video { background-position: -224px -128px; }
-.ui-icon-script { background-position: -240px -128px; }
-.ui-icon-alert { background-position: 0 -144px; }
-.ui-icon-info { background-position: -16px -144px; }
-.ui-icon-notice { background-position: -32px -144px; }
-.ui-icon-help { background-position: -48px -144px; }
-.ui-icon-check { background-position: -64px -144px; }
-.ui-icon-bullet { background-position: -80px -144px; }
-.ui-icon-radio-on { background-position: -96px -144px; }
-.ui-icon-radio-off { background-position: -112px -144px; }
-.ui-icon-pin-w { background-position: -128px -144px; }
-.ui-icon-pin-s { background-position: -144px -144px; }
-.ui-icon-play { background-position: 0 -160px; }
-.ui-icon-pause { background-position: -16px -160px; }
-.ui-icon-seek-next { background-position: -32px -160px; }
-.ui-icon-seek-prev { background-position: -48px -160px; }
-.ui-icon-seek-end { background-position: -64px -160px; }
-.ui-icon-seek-start { background-position: -80px -160px; }
-/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
-.ui-icon-seek-first { background-position: -80px -160px; }
-.ui-icon-stop { background-position: -96px -160px; }
-.ui-icon-eject { background-position: -112px -160px; }
-.ui-icon-volume-off { background-position: -128px -160px; }
-.ui-icon-volume-on { background-position: -144px -160px; }
-.ui-icon-power { background-position: 0 -176px; }
-.ui-icon-signal-diag { background-position: -16px -176px; }
-.ui-icon-signal { background-position: -32px -176px; }
-.ui-icon-battery-0 { background-position: -48px -176px; }
-.ui-icon-battery-1 { background-position: -64px -176px; }
-.ui-icon-battery-2 { background-position: -80px -176px; }
-.ui-icon-battery-3 { background-position: -96px -176px; }
-.ui-icon-circle-plus { background-position: 0 -192px; }
-.ui-icon-circle-minus { background-position: -16px -192px; }
-.ui-icon-circle-close { background-position: -32px -192px; }
-.ui-icon-circle-triangle-e { background-position: -48px -192px; }
-.ui-icon-circle-triangle-s { background-position: -64px -192px; }
-.ui-icon-circle-triangle-w { background-position: -80px -192px; }
-.ui-icon-circle-triangle-n { background-position: -96px -192px; }
-.ui-icon-circle-arrow-e { background-position: -112px -192px; }
-.ui-icon-circle-arrow-s { background-position: -128px -192px; }
-.ui-icon-circle-arrow-w { background-position: -144px -192px; }
-.ui-icon-circle-arrow-n { background-position: -160px -192px; }
-.ui-icon-circle-zoomin { background-position: -176px -192px; }
-.ui-icon-circle-zoomout { background-position: -192px -192px; }
-.ui-icon-circle-check { background-position: -208px -192px; }
-.ui-icon-circlesmall-plus { background-position: 0 -208px; }
-.ui-icon-circlesmall-minus { background-position: -16px -208px; }
-.ui-icon-circlesmall-close { background-position: -32px -208px; }
-.ui-icon-squaresmall-plus { background-position: -48px -208px; }
-.ui-icon-squaresmall-minus { background-position: -64px -208px; }
-.ui-icon-squaresmall-close { background-position: -80px -208px; }
-.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
-.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
-.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
-.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
-.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
-.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Corner radius */
-.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 0; -webkit-border-top-left-radius: 0; -khtml-border-top-left-radius: 0; border-top-left-radius: 0; }
-.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 0; -webkit-border-top-right-radius: 0; -khtml-border-top-right-radius: 0; border-top-right-radius: 0; }
-.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 0; -webkit-border-bottom-left-radius: 0; -khtml-border-bottom-left-radius: 0; border-bottom-left-radius: 0; }
-.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 0; -webkit-border-bottom-right-radius: 0; -khtml-border-bottom-right-radius: 0; border-bottom-right-radius: 0; }
-
-/* Overlays */
-.ui-widget-overlay { background: #000000; opacity: .75;filter:Alpha(Opacity=75); }
-.ui-widget-shadow { margin: -7px 0 0 -7px; padding: 7px; /* @embed */ background: #000000 url("images/ui-bg_flat_70_000000_40x100.png") 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }
\ No newline at end of file
}
context = $( this ).data( 'wikiEditor-context' );
- hasWikiEditorSurface = ( context !== undefined );
+ hasWikiEditorSurface = ( context !== undefined && context.$iframe !== undefined );
// IE selection restore voodoo
needSave = false;
// the original values
if (
mw.config.get( 'wgAction' ) === 'submit' ||
- $wpTextbox1.data( 'origtext' ) !== $wpTextbox1.val() ||
- $wpSummary.data( 'origtext' ) !== $wpSummary.val()
+ $wpTextbox1.data( 'origtext' ) !== $wpTextbox1.textSelection( 'getContents' ) ||
+ $wpSummary.data( 'origtext' ) !== $wpSummary.textSelection( 'getContents' )
) {
// Return our message
retval = mw.msg( 'editwarning-warning' );
'remoteSkinPath' => 'Vector',
'localBasePath' => __DIR__,
);
+
+// Apply module customizations
+$wgResourceModuleSkinStyles['vector'] = array(
+ 'jquery.tipsy' => 'skinStyles/jquery.tipsy.less',
+ 'jquery.ui.core' => array(
+ 'skinStyles/jquery.ui/jquery.ui.core.css',
+ 'skinStyles/jquery.ui/jquery.ui.theme.css',
+ ),
+ 'jquery.ui.accordion' => 'skinStyles/jquery.ui/jquery.ui.accordion.css',
+ 'jquery.ui.autocomplete' => 'skinStyles/jquery.ui/jquery.ui.autocomplete.css',
+ 'jquery.ui.button' => 'skinStyles/jquery.ui/jquery.ui.button.css',
+ 'jquery.ui.datepicker' => 'skinStyles/jquery.ui/jquery.ui.datepicker.css',
+ 'jquery.ui.dialog' => 'skinStyles/jquery.ui/jquery.ui.dialog.css',
+ 'jquery.ui.progressbar' => 'skinStyles/jquery.ui/jquery.ui.progressbar.css',
+ 'jquery.ui.resizable' => 'skinStyles/jquery.ui/jquery.ui.resizable.css',
+ 'jquery.ui.selectable' => 'skinStyles/jquery.ui/jquery.ui.selectable.css',
+ 'jquery.ui.slider' => 'skinStyles/jquery.ui/jquery.ui.slider.css',
+ 'jquery.ui.tabs' => 'skinStyles/jquery.ui/jquery.ui.tabs.css',
+ 'mediawiki.notification' => 'skinStyles/mediawiki.notification.less',
+ 'mediawiki.special' => 'skinStyles/mediawiki.special.less',
+ 'mediawiki.special.preferences' => 'skinStyles/mediawiki.special.preferences.less',
+ 'remoteSkinPath' => 'Vector',
+ 'localBasePath' => __DIR__,
+);
line-height: @content-line-height;
font-size: @content-font-size;
}
-
-/* Tooltips are outside of the normal body code, so this helps make the size of the text sensible */
-// FIXME: Should be part of jquery.tipsy.css
-.tipsy {
- font-size: 0.8em;
-}
+++ /dev/null
-/* mediawiki.notification */
-
-// This wrapper class is needed to ensure these rules have larger CSS
-// selector specificity than default styles
-.mediawiki {
- .mw-notification-area {
- font-size: 0.8em;
- }
-
- .mw-notification-area-layout {
- top: 7em;
- }
-
- .mw-notification {
- background-color: #fff;
- background-color: rgba(255, 255, 255, 0.93);
- padding: 0.75em 1.5em;
- border: solid 1px @content-border-color;
- border-radius: 0.75em;
- box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.125);
- }
-}
--- /dev/null
+/* Tooltips are outside of the normal body code, so this helps make the size of the text sensible */
+.tipsy {
+ font-size: 0.8em;
+}
--- /dev/null
+/*!
+ * jQuery UI Accordion 1.9.2
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Accordion#theming
+ */
+.ui-accordion .ui-accordion-header { display: block; cursor: pointer; position: relative; margin-top: 2px; padding: .5em .5em .5em .7em; zoom: 1; }
+.ui-accordion .ui-accordion-icons { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-noicons { padding-left: .7em; }
+.ui-accordion .ui-accordion-icons .ui-accordion-icons { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-header .ui-accordion-header-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; overflow: auto; zoom: 1; }
--- /dev/null
+/*!
+ * jQuery UI Autocomplete 1.9.2
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete#theming
+ */
+.ui-autocomplete {
+ position: absolute;
+ top: 0;
+ left: 0;
+ cursor: default;
+}
+.ui-autocomplete-loading { /* @embed */ background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; }
+
+/* workarounds */
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
--- /dev/null
+/*!
+ * jQuery UI Button 1.9.2
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Button#theming
+ */
+.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
+.ui-button, .ui-button:link, .ui-button:visited, .ui-button:hover, .ui-button:active { text-decoration: none; }
+.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
+button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
+.ui-button-icons-only { width: 3.4em; }
+button.ui-button-icons-only { width: 3.7em; }
+
+/*button text element */
+.ui-button .ui-button-text { display: block; line-height: 1.4; }
+.ui-button-text-only .ui-button-text { padding: .125em .25em; }
+.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
+.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
+.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
+.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
+/* no icon support for input elements, provide padding by default */
+input.ui-button { padding: .4em 1em; }
+
+/*button icon element(s) */
+.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
+.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
+.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
+.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+
+/*button sets*/
+.ui-buttonset { margin-right: 7px; }
+.ui-buttonset .ui-button { margin-left: 0; margin-right: -.4em; }
+
+/* workarounds */
+button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
+
+/* Disables the annoying dashed border Firefox puts on active buttons */
+body button.ui-button::-moz-focus-inner {
+ border: 0;
+}
+/* Give large buttons some extra padding */
+body .ui-button-large {
+ padding: 5px;
+}
+/* Use white icons for colored buttons */
+.ui-button-green .ui-icon,
+.ui-button-blue .ui-icon,
+.ui-button-red .ui-icon,
+.ui-button-orange .ui-icon {
+ /* @embed */
+ background-image: url(images/ui-icons_ffffff_256x240.png) !important;
+}
+
+/* Corner radius */
+/* This is normally handled in jquery.ui.theme.css, but in our case, the corner
+ styling of our buttons doesn't match our default widget corner styling */
+.ui-button.ui-corner-all,
+.ui-button.ui-corner-top,
+.ui-button.ui-corner-left,
+.ui-button.ui-corner-tl {
+ border-top-left-radius: 4px;
+}
+.ui-button.ui-corner-all,
+.ui-button.ui-corner-top,
+
+.ui-button.ui-corner-right,
+.ui-button.ui-corner-tr {
+ border-top-right-radius: 4px;
+}
+.ui-button.ui-corner-all,
+.ui-button.ui-corner-bottom,
+.ui-button.ui-corner-left,
+.ui-button.ui-corner-bl {
+ border-bottom-left-radius: 4px;
+}
+.ui-button.ui-corner-all,
+.ui-button.ui-corner-bottom,
+.ui-button.ui-corner-right,
+.ui-button.ui-corner-br {
+ border-bottom-right-radius: 4px;
+}
+
+body .ui-button {
+ color: #2779aa;
+ margin: 0.5em 0 0.5em 0.4em;
+ border: 1px solid #aaa !important;
+ background: #f0f0f0 !important;
+ background: -moz-linear-gradient(top, #fff 0%, #ddd 90%) !important; /* FF3.6+ */
+ background: -webkit-linear-gradient(top, #fff 0%, #ddd 90%) !important; /* Chrome10+, Safari5.1+ */
+ background: -o-linear-gradient(top, #fff 0%, #ddd 90%) !important; /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #fff 0%, #ddd 90%) !important; /* IE10+ */
+ background: linear-gradient(to bottom, #fff 0%, #ddd 90%) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dddddd', GradientType=0); /* IE6-8 */
+ cursor: pointer;
+ font-size: 1em;
+ line-height: 1.4em;
+ width: auto;
+ overflow: visible;
+ box-shadow: 0 1px 3px rgba(0,0,0,.2);
+}
+
+body .ui-button-icon-only {
+ width: 2.2em;
+}
+
+body .ui-button-icons-only {
+ width: 3.4em;
+}
+
+body .ui-button:hover {
+ color: #2779aa;
+ border-color: #bbb !important;
+ background: #fff !important;
+ background: -moz-linear-gradient(top, #fff 0%, #eee 90%) !important; /* FF3.6+ */
+ background: -webkit-linear-gradient(top, #fff 0%, #eee 90%) !important; /* Chrome10+, Safari5.1+ */
+ background: -o-linear-gradient(top, #fff 0%, #eee 90%) !important; /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #fff 0%, #eee 90%) !important; /* IE10+ */
+ background: linear-gradient(to bottom, #fff 0%, #eee 90%) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0); /* IE6-8 */
+ box-shadow: 0 1px 3px rgba(0,0,0,.1);
+}
+body .ui-button:active,
+body .ui-button:focus {
+ border-color: #8ad !important;
+ box-shadow: 0 0 1px 1px rgba(167,215,249,.5);
+}
+body .ui-button:active {
+ background: #e0e0e0 !important;
+ background: -moz-linear-gradient(top, #f0f0f0 0%, #d0d0d0 90%) !important; /* FF3.6+ */
+ background: -webkit-linear-gradient(top, #f0f0f0 0%, #d0d0d0 90%) !important; /* Chrome10+, Safari5.1+ */
+ background: -o-linear-gradient(top, #f0f0f0 0%, #d0d0d0 90%) !important; /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #f0f0f0 0%, #d0d0d0 90%) !important; /* IE10+ */
+ background: linear-gradient(to bottom, #f0f0f0 0%, #d0d0d0 90%) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f0f0f0', endColorstr='#d0d0d0', GradientType=0); /* IE6-8 */
+}
+
+/* Green buttons */
+body .ui-button-green,
+body .ui-button-green .ui-button-text {
+ color: white;
+ text-shadow: 0 -1px 1px #072;
+}
+body .ui-button.ui-button-green {
+ border-color: #294 !important;
+ background: #295 !important;
+ background: -moz-linear-gradient(top, #3c8 0%, #295 90%) !important; /* FF3.6+ */
+ background: -webkit-linear-gradient(top, #3c8 0%, #295 90%) !important; /* Chrome10+, Safari5.1+ */
+ background: -o-linear-gradient(top, #3c8 0%, #295 90%) !important; /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #3c8 0%, #295 90%) !important; /* IE10+ */
+ background: linear-gradient(to bottom, #3c8 0%, #295 90%) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#33cc88', endColorstr='#229955', GradientType=0); /* IE6-8 */
+ box-shadow: 0 1px 3px rgba(0,0,0,.3);
+}
+body .ui-button.ui-button-green:hover {
+ background: #33a055 !important;
+ background: -moz-linear-gradient(top, #44d388 0%, #33a055 90%) !important; /* FF3.6+ */
+ background: -webkit-linear-gradient(top, #44d388 0%, #33a055 90%) !important; /* Chrome10+, Safari5.1+ */
+ background: -o-linear-gradient(top, #44d388 0%, #33a055 90%) !important; /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #44d388 0%, #33a055 90%) !important; /* IE10+ */
+ background: linear-gradient(to bottom, #44d388 0%, #33a055 90%) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#44d388', endColorstr='#33a055', GradientType=0); /* IE6-8 */
+ box-shadow: 0 1px 3px rgba(0,0,0,.25);
+}
+body .ui-button.ui-button-green:active,
+body .ui-button.ui-button-green:focus {
+ border-color: #172 !important;
+ box-shadow: 0 0 2px 2px rgba(167,215,249,.75);
+}
+body .ui-button.ui-button-green:active {
+ background: #338855 !important;
+ background: -moz-linear-gradient(top, #30c080 0%, #338855 90%) !important; /* FF3.6+ */
+ background: -webkit-linear-gradient(top, #30c080 0%, #338855 90%) !important; /* Chrome10+, Safari5.1+ */
+ background: -o-linear-gradient(top, #30c080 0%, #338855 90%) !important; /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #30c080 0%, #338855 90%) !important; /* IE10+ */
+ background: linear-gradient(to bottom, #30c080 0%, #338855 90%) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#30c080', endColorstr='#338855', GradientType=0); /* IE6-8 */
+}
+
+/* Blue buttons */
+body .ui-button-blue,
+body .ui-button-blue .ui-button-text {
+ color: white;
+ text-shadow: 0 -1px 1px #037;
+}
+body .ui-button.ui-button-blue {
+ border-color: #468 !important;
+ background: #36b !important;
+ background: -moz-linear-gradient(top, #48e 0%, #36b 90%) !important; /* FF3.6+ */
+ background: -webkit-linear-gradient(top, #48e 0%, #36b 90%) !important; /* Chrome10+, Safari5.1+ */
+ background: -o-linear-gradient(top, #48e 0%, #36b 90%) !important; /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #48e 0%, #36b 90%) !important; /* IE10+ */
+ background: linear-gradient(to bottom, #48e 0%, #36b 90%) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#4488ee', endColorstr='#3366bb', GradientType=0); /* IE6-8 */
+ box-shadow: 0 1px 3px rgba(0,0,0,.35);
+}
+body .ui-button.ui-button-blue:hover {
+ background: #36c !important;
+ background: -moz-linear-gradient(top, #59e 0%, #36c 90%) !important; /* FF3.6+ */
+ background: -webkit-linear-gradient(top, #59e 0%, #36c 90%) !important; /* Chrome10+, Safari5.1+ */
+ background: -o-linear-gradient(top, #59e 0%, #36c 90%) !important; /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #59e 0%, #36c 90%) !important; /* IE10+ */
+ background: linear-gradient(to bottom, #59e 0%, #36c 90%) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5599ee', endColorstr='#3366cc', GradientType=0); /* IE6-8 */
+}
+body .ui-button.ui-button-blue:active,
+body .ui-button.ui-button-blue:focus {
+ border-color: #357 !important;
+ box-shadow: 0 0 2px 2px rgba(167,215,249,.75);
+}
+body .ui-button.ui-button-blue:active {
+ background: #3060a0 !important;
+ background: -moz-linear-gradient(top, #4080e0 0%, #3060a0 90%) !important; /* FF3.6+ */
+ background: -webkit-linear-gradient(top, #4080e0 0%, #3060a0 90%) !important; /* Chrome10+, Safari5.1+ */
+ background: -o-linear-gradient(top, #4080e0 0%, #3060a0 90%) !important; /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #4080e0 0%, #3060a0 90%) !important; /* IE10+ */
+ background: linear-gradient(to bottom, #4080e0 0%, #3060a0 90%) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#4080e0', endColorstr='#3060a0', GradientType=0); /* IE6-8 */
+}
+
+/* Red buttons */
+body .ui-button-red,
+body .ui-button-red .ui-button-text {
+ color: white;
+ text-shadow: 0 -1px 1px #700;
+}
+body .ui-button.ui-button-red {
+ border-color: #944 !important;
+ background: #a22 !important;
+ background: -moz-linear-gradient(top, #d44 0%, #a22 90%) !important; /* FF3.6+ */
+ background: -webkit-linear-gradient(top, #d44 0%, #a22 90%) !important; /* Chrome10+, Safari5.1+ */
+ background: -o-linear-gradient(top, #d44 0%, #a22 90%) !important; /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #d44 0%, #a22 90%) !important; /* IE10+ */
+ background: linear-gradient(to bottom, #d44 0%, #a22 90%) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#dd4444', endColorstr='#aa2222', GradientType=0); /* IE6-8 */
+ box-shadow: 0 1px 3px rgba(0,0,0,.35);
+}
+body .ui-button.ui-button-red:hover {
+ border-color: #a44 !important;
+ background: #b03333 !important;
+ background: -moz-linear-gradient(top, #ee4646 0%, #b03333 90%) !important; /* FF3.6+ */
+ background: -webkit-linear-gradient(top, #ee4646 0%, #b03333 90%) !important; /* Chrome10+, Safari5.1+ */
+ background: -o-linear-gradient(top, #ee4646 0%, #b03333 90%) !important; /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #ee4646 0%, #b03333 90%) !important; /* IE10+ */
+ background: linear-gradient(to bottom, #ee4646 0%, #b03333 90%) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee4646', endColorstr='#b03333', GradientType=0); /* IE6-8 */
+ box-shadow: 0 1px 3px rgba(0,0,0,.3);
+}
+body .ui-button.ui-button-red:active,
+body .ui-button.ui-button-red:focus {
+ border-color: #747 !important;
+ box-shadow: 0 0 2px 2px rgba(167,215,249,.7);
+}
+body .ui-button.ui-button-red:active {
+ background: #952020 !important;
+ background: -moz-linear-gradient(top, #d04545 0%, #952020 90%) !important; /* FF3.6+ */
+ background: -webkit-linear-gradient(top, #d04545 0%, #952020 90%) !important; /* Chrome10+, Safari5.1+ */
+ background: -o-linear-gradient(top, #d04545 0%, #952020 90%) !important; /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #d04545 0%, #952020 90%) !important; /* IE10+ */
+ background: linear-gradient(to bottom, #d04545 0%, #952020 90%) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#d04545', endColorstr='#952020', GradientType=0); /* IE6-8 */
+}
+
+/* Disabled buttons */
+body .ui-button-green.disabled,
+body .ui-button-green.disabled:hover,
+body .ui-button-green.disabled:active,
+body .ui-button-green.disabled:focus,
+body .ui-button-blue.disabled,
+body .ui-button-blue.disabled:hover,
+body .ui-button-blue.disabled:active,
+body .ui-button-blue.disabled:focus,
+body .ui-button-red.disabled,
+body .ui-button-red.disabled:hover,
+body .ui-button-red.disabled:active,
+body .ui-button-red.disabled:focus,
+body .ui-button.disabled,
+body .ui-button.disabled:hover {
+ color: #aaa;
+ border-color: #ccc !important;
+ background: #eee !important;
+ background: -moz-linear-gradient(top, #f6f6f6 0%, #eee 90%) !important; /* FF3.6+ */
+ background: -webkit-linear-gradient(top, #f6f6f6 0%, #eee 90%) !important; /* Chrome10+, Safari5.1+ */
+ background: -o-linear-gradient(top, #f6f6f6 0%, #eee 90%) !important; /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #f6f6f6 0%, #eee 90%) !important; /* IE10+ */
+ background: linear-gradient(to bottom, #f6f6f6 0%, #eee 90%) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f6f6f6', endColorstr='#eeeeee', GradientType=0); /* IE6-8 */
+ box-shadow: 0 1px 3px rgba(0,0,0,0);
+}
+body .ui-button-green.disabled .ui-button-text,
+body .ui-button-blue.disabled .ui-button-text,
+body .ui-button-red.disabled .ui-button-text {
+ color: #aaa;
+ text-shadow: 0 1px 1px #fff;
+}
--- /dev/null
+/*!
+ * jQuery UI CSS Framework 1.9.2
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
+.ui-helper-clearfix:after { clear: both; }
+.ui-helper-clearfix { zoom: 1; }
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
--- /dev/null
+/*!
+ * jQuery UI Datepicker 1.9.2
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Datepicker#theming
+ */
+.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; padding:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-top: 1px solid #DDDDDD; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
+
+/* RTL support */
+/* @noflip */ .ui-datepicker-rtl { direction: rtl; }
+/* @noflip */ .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+/* @noflip */ .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+/* @noflip */ .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+/* @noflip */ .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+/* @noflip */ .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+/* @noflip */ .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+/* @noflip */ .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+/* @noflip */ .ui-datepicker-rtl .ui-datepicker-group { float:right; }
+/* @noflip */ .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+/* @noflip */ .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+ position: absolute; /*must have*/
+ z-index: -1; /*must have*/
+ filter: mask(); /*must have*/
+ top: -4px; /*must have*/
+ left: -4px; /*must have*/
+ width: 200px; /*must have*/
+ height: 200px; /*must have*/
+}
\ No newline at end of file
--- /dev/null
+/*!
+ * jQuery UI Dialog 1.9.2
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Dialog#theming
+ */
+.ui-dialog { position: absolute; top: 0; left: 0; padding: 0; width: 300px; }
+.ui-dialog .ui-dialog-titlebar { padding: .75em; position: relative; }
+.ui-dialog .ui-dialog-title { float: left; margin: 0; }
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .75em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
+.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
+
+/* Customizations */
+body .ui-dialog .ui-dialog-titlebar-close:hover {
+ text-decoration: none;
+}
+body .ui-dialog .ui-dialog-content .status-invalid input {
+ border: 2px solid red;
+ padding: 2px 1px;
+}
+body .ui-dialog .ui-dialog-titlebar {
+ padding: 0.9em 1.4em 0.6em !important;
+}
+body .ui-dialog .ui-widget-header {
+ /* @embed */
+ background: #f0f0f0 url(images/titlebar-fade.png) repeat-x scroll 50% 100% !important;
+}
+/* FIXME: Should just update the icon sprite if we're keeping this X */
+body .ui-dialog .ui-icon-closethick {
+ /* @embed */
+ background: url(images/close.png) no-repeat 50% 50% !important;
+}
+body .ui-dialog .ui-dialog-buttonpane {
+ margin-top: 0 !important;
+ padding:0.3em 1.4em 0.5em 1.4em !important;
+}
--- /dev/null
+/*!
+ * jQuery UI Progressbar 1.9.2
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Progressbar#theming
+ */
+.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file
--- /dev/null
+/*!
+ * jQuery UI Resizable 1.9.2
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Resizable#theming
+ */
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; }
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
+/* @noflip */
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
+/* @noflip */
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
+/* @noflip */
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+/* @noflip */
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+/* @noflip */
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+/* @noflip */
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
\ No newline at end of file
--- /dev/null
+/*!
+ * jQuery UI Selectable 1.9.2
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Selectable#theming
+ */
+.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
--- /dev/null
+/*!
+ * jQuery UI Slider 1.9.2
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider#theming
+ */
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }
\ No newline at end of file
--- /dev/null
+/*!
+ * jQuery UI Tabs 1.9.2
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Tabs#theming
+ */
+.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
+.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 0; margin: 1px .2em 0 0; border-bottom: 0; padding: 0; white-space: nowrap; }
+.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-active { margin-bottom: -1px; padding-bottom: 1px; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-active a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-tabs-loading a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
--- /dev/null
+/*!
+ * jQuery UI CSS Framework 1.9.2
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=sans-serif&fwDefault=normal&fsDefault=1.0em&cornerRadius=3px&bgColorHeader=ffffff&bgTextureHeader=highlight_soft&bgImgOpacityHeader=100&borderColorHeader=aed0ea&fcHeader=222222&iconColorHeader=72a7cf&bgColorContent=f2f5f7&bgTextureContent=highlight_hard&bgImgOpacityContent=100&borderColorContent=cccccc&fcContent=362b36&iconColorContent=72a7cf&bgColorDefault=d7ebf9&bgTextureDefault=highlight_hard&bgImgOpacityDefault=80&borderColorDefault=aed0ea&fcDefault=2779aa&iconColorDefault=3d80b3&bgColorHover=e4f1fb&bgTextureHover=highlight_soft&bgImgOpacityHover=100&borderColorHover=74b2e2&fcHover=0070a3&iconColorHover=2694e8&bgColorActive=f0f0f0&bgTextureActive=inset_hard&bgImgOpacityActive=100&borderColorActive=cccccc&fcActive=000000&iconColorActive=666666&bgColorHighlight=ffef8f&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=25&borderColorHighlight=f9dd34&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=cd0a0a&bgTextureError=flat&bgImgOpacityError=15&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffffff&bgColorOverlay=000000&bgTextureOverlay=glow_ball&bgImgOpacityOverlay=100&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=70&opacityShadow=20&thicknessShadow=7px&offsetTopShadow=-7px&offsetLeftShadow=-7px&cornerRadiusShadow=8px
+ */
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: sans-serif; font-size: 0.8em; }
+.ui-widget .ui-widget { font-size: 1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #cccccc; /* @embed */ background: #f2f5f7 url("images/ui-bg_highlight-hard_100_f2f5f7_1x100.png") 50% top repeat-x; color: #362b36; }
+.ui-widget-header { border-bottom: 1px solid #bbbbbb; line-height: 1em; /* @embed */ background: #ffffff url("images/ui-bg_highlight-soft_100_ffffff_1x100.png") 50% 50% repeat-x; color: #222222; font-weight: bold; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #aed0ea; /* @embed */ background: #d7ebf9 url("images/ui-bg_highlight-hard_80_d7ebf9_1x100.png") 50% 50% repeat-x; font-weight: normal; color: #2779aa; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2779aa; text-decoration: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #74b2e2; /* @embed */ background: #e4f1fb url("images/ui-bg_highlight-soft_100_e4f1fb_1x100.png") 50% 50% repeat-x; font-weight: normal; color: #0070a3; }
+.ui-state-hover a, .ui-state-hover a:hover, .ui-state-hover a:link, .ui-state-hover a:visited { color: #0070a3; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #cccccc; background: #f0f0f0 /* @embed */ url("images/ui-bg_inset-hard_100_f0f0f0_1x100.png") 50% 50% repeat-x; font-weight: normal; color: #000000; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #000000; text-decoration: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #f9dd34; background: #ffef8f /* @embed */ url("images/ui-bg_highlight-soft_25_ffef8f_1x100.png") 50% top repeat-x; color: #363636; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #cd0a0a /* @embed */ url("images/ui-bg_flat_15_cd0a0a_40x100.png") 50% 50% repeat-x; color: #ffffff; }
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+.ui-state-disabled .ui-icon { filter:Alpha(Opacity=35); } /* For IE8 - See #6059 */
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; }
+.ui-icon, .ui-widget-content .ui-icon, .ui-widget-header .ui-icon { /* @embed */ background-image: url("images/ui-icons_72a7cf_256x240.png"); }
+.ui-state-default .ui-icon { /* @embed */ background-image: url("images/ui-icons_3d80b3_256x240.png"); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon { /* @embed */ background-image: url("images/ui-icons_2694e8_256x240.png"); }
+.ui-state-active .ui-icon { /* @embed */ background-image: url("images/ui-icons_666666_256x240.png"); }
+.ui-state-highlight .ui-icon { /* @embed */ background-image: url("images/ui-icons_2e83ff_256x240.png"); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon { /* @embed */ background-image: url("images/ui-icons_ffffff_256x240.png"); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-on { background-position: -96px -144px; }
+.ui-icon-radio-off { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 0; -webkit-border-top-left-radius: 0; -khtml-border-top-left-radius: 0; border-top-left-radius: 0; }
+.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 0; -webkit-border-top-right-radius: 0; -khtml-border-top-right-radius: 0; border-top-right-radius: 0; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 0; -webkit-border-bottom-left-radius: 0; -khtml-border-bottom-left-radius: 0; border-bottom-left-radius: 0; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 0; -webkit-border-bottom-right-radius: 0; -khtml-border-bottom-right-radius: 0; border-bottom-right-radius: 0; }
+
+/* Overlays */
+.ui-widget-overlay { background: #000000; opacity: .75;filter:Alpha(Opacity=75); }
+.ui-widget-shadow { margin: -7px 0 0 -7px; padding: 7px; /* @embed */ background: #000000 url("images/ui-bg_flat_70_000000_40x100.png") 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }
\ No newline at end of file
--- /dev/null
+@import "../variables";
+
+/* mediawiki.notification */
+
+// This wrapper class is needed to ensure these rules have larger CSS
+// selector specificity than default styles
+.mediawiki {
+ .mw-notification-area {
+ font-size: 0.8em;
+ }
+
+ .mw-notification-area-layout {
+ top: 7em;
+ }
+
+ .mw-notification {
+ background-color: #fff;
+ background-color: rgba(255, 255, 255, 0.93);
+ padding: 0.75em 1.5em;
+ border: solid 1px @content-border-color;
+ border-radius: 0.75em;
+ box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.125);
+ }
+}
--- /dev/null
+/**
+ * Adjusts for decreased margin-bottom for h2 elements inside #content div
+ * introduced in March / April 2014 typography update.
+ */
+table.mw-specialpages-table {
+ margin-top: 0;
+}
--- /dev/null
+@import "mediawiki.mixins";
+@import "../variables";
+
+/**
+ * The following code is highly modified from monobook. It would be nice if the
+ * preftoc id was more human readable like preferences-toc for instance,
+ * howerver this would require backporting the other skins.
+ */
+
+#preftoc {
+ /* Tabs */
+ width: 100%;
+ float: left;
+ clear: both;
+ margin: 0 !important;
+ padding: 0 !important;
+ .background-image('images/preferences/break.png');
+ background-position: bottom left;
+ background-repeat: no-repeat;
+
+ li {
+ /* Tab */
+ float: left;
+ margin: 0;
+ padding: 0;
+ padding-right: 1px;
+ height: 2.25em;
+ white-space: nowrap;
+ list-style-type: none;
+ list-style-image: none;
+ .background-image('images/preferences/break.png');
+ background-position: bottom right;
+ background-repeat: no-repeat;
+
+ /* Sadly, IE6 won't understand this */
+ &:first-child {
+ margin-left: 1px;
+ }
+
+ &.selected {
+ a {
+ .background-image('images/preferences/fade.png');
+ background-position: bottom;
+ background-repeat: repeat-x;
+ color: #333;
+ text-decoration: none;
+ }
+ }
+ }
+
+ a,
+ a:active {
+ display: inline-block;
+ position: relative;
+ color: @menu-link-color;
+ padding: 0.5em;
+ text-decoration: none;
+ background-image: none;
+ font-size: 0.9em;
+ }
+
+ a:hover,
+ a:focus {
+ text-decoration: underline;
+ }
+}
+
+#preferences {
+ float: left;
+ width: 100%;
+ margin: 0;
+ margin-top: -2px;
+ clear: both;
+ border: solid 1px #ccc;
+ background-color: #fafafa;
+
+ fieldset {
+ border: none;
+ border-top: solid 1px #ccc;
+
+ &.prefsection {
+ border: none;
+ padding: 0;
+ margin: 1em;
+
+ legend.mainLegend {
+ display: none;
+ }
+ }
+ }
+
+ legend {
+ color: #666;
+ }
+
+ td {
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+ }
+
+ div.mw-prefs-buttons {
+ padding: 1em;
+
+ input {
+ margin-right: 0.25em;
+ }
+ }
+}
+
+.htmlform-tip {
+ font-size: x-small;
+ padding: .2em 2em;
+ color: #666;
+}
+++ /dev/null
-/**
- * Adjusts for decreased margin-bottom for h2 elements inside #content div
- * introduced in March / April 2014 typography update.
- */
-table.mw-specialpages-table {
- margin-top: 0;
-}
+++ /dev/null
-@import "mediawiki.mixins";
-@import "variables";
-
-/**
- * The following code is highly modified from monobook. It would be nice if the
- * preftoc id was more human readable like preferences-toc for instance,
- * howerver this would require backporting the other skins.
- */
-
-#preftoc {
- /* Tabs */
- width: 100%;
- float: left;
- clear: both;
- margin: 0 !important;
- padding: 0 !important;
- .background-image('images/preferences/break.png');
- background-position: bottom left;
- background-repeat: no-repeat;
-
- li {
- /* Tab */
- float: left;
- margin: 0;
- padding: 0;
- padding-right: 1px;
- height: 2.25em;
- white-space: nowrap;
- list-style-type: none;
- list-style-image: none;
- .background-image('images/preferences/break.png');
- background-position: bottom right;
- background-repeat: no-repeat;
-
- /* Sadly, IE6 won't understand this */
- &:first-child {
- margin-left: 1px;
- }
-
- &.selected {
- a {
- .background-image('images/preferences/fade.png');
- background-position: bottom;
- background-repeat: repeat-x;
- color: #333;
- text-decoration: none;
- }
- }
- }
-
- a,
- a:active {
- display: inline-block;
- position: relative;
- color: @menu-link-color;
- padding: 0.5em;
- text-decoration: none;
- background-image: none;
- font-size: 0.9em;
- }
-
- a:hover,
- a:focus {
- text-decoration: underline;
- }
-}
-
-#preferences {
- float: left;
- width: 100%;
- margin: 0;
- margin-top: -2px;
- clear: both;
- border: solid 1px #ccc;
- background-color: #fafafa;
-
- fieldset {
- border: none;
- border-top: solid 1px #ccc;
-
- &.prefsection {
- border: none;
- padding: 0;
- margin: 1em;
-
- legend.mainLegend {
- display: none;
- }
- }
- }
-
- legend {
- color: #666;
- }
-
- td {
- padding-left: 0.5em;
- padding-right: 0.5em;
- }
-
- div.mw-prefs-buttons {
- padding: 1em;
-
- input {
- margin-right: 0.25em;
- }
- }
-}
-
-.htmlform-tip {
- font-size: x-small;
- padding: .2em 2em;
- color: #666;
-}
'MediaWikiPHPUnitCommand' => "$testDir/phpunit/MediaWikiPHPUnitCommand.php",
'MediaWikiPHPUnitTestListener' => "$testDir/phpunit/MediaWikiPHPUnitTestListener.php",
'MediaWikiLangTestCase' => "$testDir/phpunit/MediaWikiLangTestCase.php",
+ 'MediaWikiPasswordTestCase' => "$testDir/phpunit/MediaWikiPasswordTestCase.php",
'ResourceLoaderTestCase' => "$testDir/phpunit/ResourceLoaderTestCase.php",
'ResourceLoaderTestModule' => "$testDir/phpunit/ResourceLoaderTestCase.php",
'ResourceLoaderFileModuleTestModule' => "$testDir/phpunit/ResourceLoaderTestCase.php",
--- /dev/null
+<?php
+/**
+ * Testing framework for the password hashes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * @since 1.23
+ */
+abstract class MediaWikiPasswordTestCase extends MediaWikiTestCase {
+ /**
+ * @var PasswordFactory
+ */
+ protected $passwordFactory;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->passwordFactory = new PasswordFactory();
+ foreach ( $this->getTypeConfigs() as $type => $config ) {
+ $this->passwordFactory->register( $type, $config );
+ }
+ }
+
+ /**
+ * Return an array of configs to be used for this class's password type.
+ *
+ * @return array[]
+ */
+ abstract protected function getTypeConfigs();
+
+ /**
+ * An array of tests in the form of (bool, string, string), where the first
+ * element is whether the second parameter (a password hash) and the third
+ * parameter (a password) should match.
+ *
+ * @return array
+ */
+ abstract public function providePasswordTests();
+
+ /**
+ * @dataProvider providePasswordTests
+ */
+ public function testHashing( $shouldMatch, $hash, $password ) {
+ $hash = $this->passwordFactory->newFromCiphertext( $hash );
+ $password = $this->passwordFactory->newFromPlaintext( $password, $hash );
+ $this->assertSame( $shouldMatch, $hash->equals( $password ) );
+ }
+
+ /**
+ * @dataProvider providePasswordTests
+ */
+ public function testStringSerialization( $shouldMatch, $hash, $password ) {
+ $hashObj = $this->passwordFactory->newFromCiphertext( $hash );
+ $serialized = $hashObj->toString();
+ $unserialized = $this->passwordFactory->newFromCiphertext( $serialized );
+ $this->assertTrue( $hashObj->equals( $unserialized ) );
+ }
+
+ /**
+ * @dataProvider providePasswordTests
+ * @covers InvalidPassword::equals
+ * @covers InvalidPassword::toString
+ */
+ public function testInvalidUnequalNormal( $shouldMatch, $hash, $password ) {
+ $invalid = $this->passwordFactory->newFromCiphertext( null );
+ $normal = $this->passwordFactory->newFromCiphertext( $hash );
+
+ $this->assertFalse( $invalid->equals( $normal ) );
+ $this->assertFalse( $normal->equals( $invalid ) );
+ }
+}
--- /dev/null
+<?php
+/**
+ * Testing framework for the Password infrastructure
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+class PasswordTest extends MediaWikiTestCase {
+ /**
+ * @covers InvalidPassword::equals
+ */
+ public function testInvalidUnequalInvalid() {
+ $invalid1 = User::getPasswordFactory()->newFromCiphertext( null );
+ $invalid2 = User::getPasswordFactory()->newFromCiphertext( null );
+
+ $this->assertFalse( $invalid1->equals( $invalid2 ) );
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @group large
+ */
+class BcryptPasswordTestCase extends MediaWikiPasswordTestCase {
+ protected function getTypeConfigs() {
+ return array( 'bcrypt' => array(
+ 'class' => 'BcryptPassword',
+ 'cost' => 9,
+ ) );
+ }
+
+ public function providePasswordTests() {
+ /** @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong */
+ return array(
+ // Tests from glibc bcrypt implementation
+ array( true, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW', "U*U" ),
+ array( true, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$VGOzA784oUp/Z0DY336zx7pLYAy0lwK', "U*U*" ),
+ array( true, ':bcrypt:5$XXXXXXXXXXXXXXXXXXXXXO$AcXxm9kjPGEMsLznoKqmqw7tc8WCx4a', "U*U*U" ),
+ array( true, ':bcrypt:5$abcdefghijklmnopqrstuu$5s2v8.iXieOjg/.AySBTTZIIVFJeBui', "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789chars after 72 are ignored" ),
+ array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$CE5elHaaO4EbggVDjb8P19RukzXSM3e', "\xff\xff\xa3" ),
+ array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq', "\xa3" ),
+ array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq', "\xa3" ),
+ array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$o./n25XVfn6oAPaUvHe.Csk4zRfsYPi', "\xff\xa334\xff\xff\xff\xa3345" ),
+ array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$nRht2l/HRhr6zmCp9vYUvvsqynflf9e', "\xff\xa3345" ),
+ array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$nRht2l/HRhr6zmCp9vYUvvsqynflf9e', "\xff\xa3345" ),
+ array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$6IflQkJytoRVc1yuaNtHfiuq.FRlSIS', "\xa3ab" ),
+ array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$6IflQkJytoRVc1yuaNtHfiuq.FRlSIS', "\xa3ab" ),
+ array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6', "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaachars after 72 are ignored as usual" ),
+ array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy', "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" ),
+ array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe', "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" ),
+ array( true, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy', "" ),
+ // One or two false sanity tests
+ array( false, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW', "UXU" ),
+ array( false, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW', "" ),
+ );
+ /** @codingStandardsIgnoreEnd */
+ }
+}
--- /dev/null
+<?php
+
+class LayeredParameterizedPasswordTest extends MediaWikiPasswordTestCase {
+ protected function getTypeConfigs() {
+ return array(
+ 'testLargeLayeredTop' => array(
+ 'class' => 'LayeredParameterizedPassword',
+ 'types' => array(
+ 'testLargeLayeredBottom',
+ 'testLargeLayeredBottom',
+ 'testLargeLayeredBottom',
+ 'testLargeLayeredBottom',
+ 'testLargeLayeredFinal',
+ ),
+ ),
+ 'testLargeLayeredBottom' => array(
+ 'class' => 'Pbkdf2Password',
+ 'algo' => 'sha512',
+ 'cost' => 1024,
+ 'length' => 512,
+ ),
+ 'testLargeLayeredFinal' => array(
+ 'class' => 'BcryptPassword',
+ 'cost' => 5,
+ )
+ );
+ }
+
+ public function providePasswordTests() {
+ /** @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong */
+ return array(
+ array( true, ':testLargeLayeredTop:sha512:1024:512!sha512:1024:512!sha512:1024:512!sha512:1024:512!5!vnRy+2SrSA0fHt3dwhTP5g==!AVnwfZsAQjn+gULv7FSGjA==!xvHUX3WcpkeSn1lvjWcvBg==!It+OC/N9tu+d3ByHhuB0BQ==!Tb.gqUOiD.aWktVwHM.Q/O!7CcyMfXUPky5ptyATJsR2nq3vUqtnBC', 'testPassword123' ),
+ );
+ /** @codingStandardsIgnoreEnd */
+ }
+
+ /**
+ * @covers LayeredParameterizedPassword::partialCrypt
+ */
+ public function testLargeLayeredPartialUpdate() {
+ /** @var ParameterizedPassword $partialPassword */
+ $partialPassword = $this->passwordFactory->newFromType( 'testLargeLayeredBottom' );
+ $partialPassword->crypt( 'testPassword123' );
+
+ /** @var LayeredParameterizedPassword $totalPassword */
+ $totalPassword = $this->passwordFactory->newFromType( 'testLargeLayeredTop' );
+ $totalPassword->partialCrypt( $partialPassword );
+
+ $this->assertTrue( $totalPassword->equals( 'testPassword123' ) );
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @group large
+ */
+class Pbkdf2PasswordTest extends MediaWikiPasswordTestCase {
+ protected function getTypeConfigs() {
+ return array( 'pbkdf2' => array(
+ 'class' => 'Pbkdf2Password',
+ 'algo' => 'sha256',
+ 'cost' => '10000',
+ 'length' => '128',
+ ) );
+ }
+
+ public function providePasswordTests() {
+ return array(
+ array( true, ":pbkdf2:sha1:1:20:c2FsdA==:DGDID5YfDnHzqbUkr2ASBi/gN6Y=", 'password' ),
+ array( true, ":pbkdf2:sha1:2:20:c2FsdA==:6mwBTcctb4zNHtkqzh1B8NjeiVc=", 'password' ),
+ array( true, ":pbkdf2:sha1:4096:20:c2FsdA==:SwB5AbdlSJq+rUnZJvch0GWkKcE=", 'password' ),
+ array( true, ":pbkdf2:sha1:4096:16:c2EAbHQ=:Vvpqp1VICZ3MN9fwNCXgww==", "pass\x00word" ),
+ );
+ }
+}
$cases[] = array(
$method->invoke( $module, $file ),
$moduleName,
- $file,
+ ( $file instanceof ResourceLoaderFilePath ? $file->getPath() : $file ),
);
}
}